#include <dali/public-api/object/type-registry.h>
#include <dali/integration-api/debug.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/layouts/layout-engine.h>
+#include <dali-toolkit/public-api/text/rendering/basic/text-basic-renderer.h> // TODO - Get from RendererFactory
+
+using Dali::Toolkit::Text::LayoutEngine;
+
namespace
{
namespace Toolkit
{
-const Property::Index TextLabel::PROPERTY_TEXT( Internal::TextLabel::TEXTLABEL_PROPERTY_START_INDEX );
+const Property::Index TextLabel::PROPERTY_TEXT( Internal::TextLabel::TEXTLABEL_PROPERTY_START_INDEX );
+const Property::Index TextLabel::PROPERTY_MULTI_LINE( Internal::TextLabel::TEXTLABEL_PROPERTY_START_INDEX + 1 );
namespace Internal
{
TypeRegistration mType( typeid(Toolkit::TextLabel), typeid(Toolkit::Control), Create );
-PropertyRegistration property1( mType, "text", Toolkit::TextLabel::PROPERTY_TEXT, Property::STRING, &TextLabel::SetProperty, &TextLabel::GetProperty );
+PropertyRegistration property1( mType, "text", Toolkit::TextLabel::PROPERTY_TEXT, Property::STRING, &TextLabel::SetProperty, &TextLabel::GetProperty );
+PropertyRegistration property2( mType, "multi-line", Toolkit::TextLabel::PROPERTY_MULTI_LINE, Property::STRING, &TextLabel::SetProperty, &TextLabel::GetProperty );
} // namespace
labelImpl.SetText( value.Get< std::string >() );
break;
}
+ case Toolkit::TextLabel::PROPERTY_MULTI_LINE:
+ {
+ labelImpl.SetMultiLine( value.Get< bool >() );
+ break;
+ }
}
}
}
mController = Text::Controller::New();
}
-void TextLabel::SetText( const std::string& text )
+void TextLabel::OnRelayout( const Vector2& size, ActorSizeContainer& container )
{
- if( mController )
+ if( mController->Relayout( size ) )
{
- // The Controller updates the View for the renderer
- mController->SetText( text );
+ if( !mRenderer )
+ {
+ // TODO - Get from RendererFactory
+ mRenderer = Dali::Toolkit::Text::BasicRenderer::New();
+ }
if( mRenderer )
{
}
}
+void TextLabel::SetText( const std::string& text )
+{
+ if( mController )
+ {
+ // The Controller updates the View for the renderer
+ mController->SetText( text );
+ }
+}
+
+void TextLabel::SetMultiLine( bool multiLine )
+{
+ if( mController )
+ {
+ if( multiLine )
+ {
+ mController->GetLayoutEngine().SetLayout( LayoutEngine::MULTI_LINE_BOX );
+ }
+ else
+ {
+ mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
+ }
+ }
+}
+
TextLabel::TextLabel()
: Control( ControlBehaviour( CONTROL_BEHAVIOUR_NONE ) )
{
*/
virtual void OnInitialize();
+ /**
+ * @copydoc Control::OnInitialize()
+ */
+ virtual void OnRelayout( const Vector2& size, ActorSizeContainer& container );
+
private: // Implementation
/**
void SetText( const std::string& text );
/**
+ * Helper for SetProperty.
+ * @param[in] multiLine The new "multi-line" property value.
+ */
+ void SetMultiLine( bool multiLine );
+
+ /**
* Construct a new TextLabel.
*/
TextLabel();
$(toolkit_base_src_dir)/focus-manager/keyboard-focus-manager-impl.cpp \
$(toolkit_base_src_dir)/focus-manager/keyinput-focus-manager-impl.cpp \
$(toolkit_base_src_dir)/styling/style-manager-impl.cpp \
+ $(toolkit_base_src_dir)/text/multi-language-support-impl.cpp \
$(toolkit_base_src_dir)/builder/builder-impl.cpp \
$(toolkit_base_src_dir)/builder/builder-animations.cpp \
$(toolkit_base_src_dir)/builder/builder-set-property.cpp \
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/multi-language-support-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/singleton-service.h>
+#include <dali-toolkit/public-api/text/logical-model.h>
+#include <dali-toolkit/public-api/text/font-run.h>
+#include <dali-toolkit/public-api/text/script.h>
+#include <dali-toolkit/public-api/text/script-run.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Retrieves the font Id from the font run for a given character's @p index.
+ *
+ * If the character's index exceeds the current font run it increases the iterator to get the next one.
+ *
+ * @param[in] index The character's index.
+ * @param[in,out] fontRunIt Iterator to the current font run.
+ * @param[in] fontRunEndIt Iterator to one after the last font run.
+ *
+ * @return The font id.
+ */
+FontId GetFontId( Length index,
+ Vector<FontRun>::ConstIterator& fontRunIt,
+ const Vector<FontRun>::ConstIterator& fontRunEndIt )
+{
+ FontId fontId = 0u;
+
+ if( fontRunIt != fontRunEndIt )
+ {
+ const FontRun& fontRun = *fontRunIt;
+
+ if( ( index >= fontRun.characterRun.characterIndex ) &&
+ ( index < fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) )
+ {
+ fontId = fontRun.fontId;
+ }
+
+ if( index == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters )
+ {
+ // All the characters of the current run have been traversed. Get the next one for the next iteration.
+ ++fontRunIt;
+ }
+ }
+
+ return fontId;
+}
+
+/**
+ * @brief Retrieves the script Id from the script run for a given character's @p index.
+ *
+ * If the character's index exceeds the current script run it increases the iterator to get the next one.
+ *
+ * @param[in] index The character's index.
+ * @param[in,out] scriptRunIt Iterator to the current font run.
+ * @param[in] scriptRunEndIt Iterator to one after the last script run.
+ *
+ * @return The script.
+ */
+Script GetScript( Length index,
+ Vector<ScriptRun>::ConstIterator& scriptRunIt,
+ const Vector<ScriptRun>::ConstIterator& scriptRunEndIt )
+{
+ Script script = TextAbstraction::UNKNOWN;
+
+ if( scriptRunIt != scriptRunEndIt )
+ {
+ const ScriptRun& scriptRun = *scriptRunIt;
+
+ if( ( index >= scriptRun.characterRun.characterIndex ) &&
+ ( index < scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) )
+ {
+ script = scriptRun.script;
+ }
+
+ if( index == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
+ {
+ // All the characters of the current run have been traversed. Get the next one for the next iteration.
+ ++scriptRunIt;
+ }
+ }
+
+ return script;
+}
+
+bool ValidateFontsPerScript::FindValidFont( FontId fontId ) const
+{
+ for( Vector<FontId>::ConstIterator it = mValidFonts.Begin(),
+ endIt = mValidFonts.End();
+ it != endIt;
+ ++it )
+ {
+ if( fontId == *it )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+MultilanguageSupport::MultilanguageSupport()
+: mDefaultFontPerScriptCache(),
+ mValidFontsPerScriptCache()
+{
+ // Initializes the default font cache to zero (invalid font).
+ // Reserves space to cache the default fonts and access them with the script as an index.
+ mDefaultFontPerScriptCache.Resize( TextAbstraction::UNKNOWN, 0u );
+
+ // Initializes the valid fonts cache to NULL (no valid fonts).
+ // Reserves space to cache the valid fonts and access them with the script as an index.
+ mValidFontsPerScriptCache.Resize( TextAbstraction::UNKNOWN, NULL );
+}
+
+MultilanguageSupport::~MultilanguageSupport()
+{
+ // Destroy the valid fonts per script cache.
+
+ for( Vector<ValidateFontsPerScript*>::Iterator it = mValidFontsPerScriptCache.Begin(),
+ endIt = mValidFontsPerScriptCache.End();
+ it != endIt;
+ ++it )
+ {
+ delete *it;
+ }
+}
+
+Text::MultilanguageSupport MultilanguageSupport::Get()
+{
+ Text::MultilanguageSupport multilanguageSupportHandle;
+
+ SingletonService service( SingletonService::Get() );
+ if( service )
+ {
+ // Check whether the singleton is already created
+ Dali::BaseHandle handle = service.GetSingleton( typeid( Text::MultilanguageSupport ) );
+ if( handle )
+ {
+ // If so, downcast the handle
+ MultilanguageSupport* impl = dynamic_cast< Internal::MultilanguageSupport* >( handle.GetObjectPtr() );
+ multilanguageSupportHandle = Text::MultilanguageSupport( impl );
+ }
+ else // create and register the object
+ {
+ multilanguageSupportHandle = Text::MultilanguageSupport( new MultilanguageSupport );
+ service.Register( typeid( multilanguageSupportHandle ), multilanguageSupportHandle );
+ }
+ }
+
+ return multilanguageSupportHandle;
+}
+
+void MultilanguageSupport::SetScripts( LogicalModel& model )
+{
+ // 1) Retrieve the text from the model.
+ const Length numberOfCharacters = model.GetNumberOfCharacters();
+
+ if( 0u == numberOfCharacters )
+ {
+ // Nothing to do if there are no characters.
+ return;
+ }
+
+ Vector<Character> text;
+ text.Resize( numberOfCharacters );
+
+ model.GetText( 0u,
+ text.Begin(),
+ numberOfCharacters );
+
+ // 2) Traverse all characters and set the scripts.
+
+ // Stores the current script run.
+ ScriptRun currentScriptRun;
+ currentScriptRun.characterRun.characterIndex = 0u;
+ currentScriptRun.characterRun.numberOfCharacters = 0u;
+ currentScriptRun.script = TextAbstraction::UNKNOWN;
+
+ // Temporary stores the script runs.
+ std::vector<ScriptRun> scriptRuns;
+ scriptRuns.reserve( numberOfCharacters << 2u ); // To reduce the number of reallocations.
+
+ for( Vector<Character>::ConstIterator it = text.Begin(),
+ endIt = text.End();
+ it != endIt;
+ ++it )
+ {
+ const Character character = *it;
+
+ Script script = GetCharacterScript( character );
+
+ if( TextAbstraction::UNKNOWN == script )
+ {
+ script = TextAbstraction::LATIN;
+ DALI_ASSERT_DEBUG( !"MultilanguageSupport::SetScripts. Unkown script!" );
+ }
+
+ if( script != currentScriptRun.script )
+ {
+ // Current run needs to be stored and a new one initialized.
+
+ if( 0u != currentScriptRun.characterRun.numberOfCharacters )
+ {
+ // Store the script run.
+ scriptRuns.push_back( currentScriptRun );
+ }
+
+ // Initialize the new one.
+ currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters;
+ currentScriptRun.characterRun.numberOfCharacters = 0u;
+ currentScriptRun.script = script;
+ }
+
+ // Add one more character to the run.
+ ++currentScriptRun.characterRun.numberOfCharacters;
+ }
+
+ if( 0u != currentScriptRun.characterRun.numberOfCharacters )
+ {
+ // Store the last run.
+ scriptRuns.push_back( currentScriptRun );
+ }
+
+ // 3) Set the script runs into the model.
+
+ model.SetScripts( &scriptRuns[0u],
+ scriptRuns.size() );
+}
+
+void MultilanguageSupport::ValidateFonts( LogicalModel& model )
+{
+ // 1) Retrieve the text from the model.
+ const Length numberOfCharacters = model.GetNumberOfCharacters();
+
+ if( 0u == numberOfCharacters )
+ {
+ // Nothing to do if there are no characters.
+ return;
+ }
+
+ Vector<Character> text;
+ text.Resize( numberOfCharacters );
+
+ Character* textBuffer = text.Begin();
+ model.GetText( 0u,
+ textBuffer,
+ numberOfCharacters );
+
+ // 2) Retrieve any font previously set.
+
+ const Length numberOfFontRuns = model.GetNumberOfFontRuns( 0u, numberOfCharacters );
+
+ Vector<FontRun> fontRuns;
+ fontRuns.Reserve( numberOfFontRuns );
+
+ FontRun* fontRunsBuffer = fontRuns.Begin();
+ model.GetFontRuns( fontRunsBuffer,
+ 0u,
+ numberOfCharacters );
+
+ // 3) Retrieve the scripts from the model.
+
+ const Length numberOfScriptRuns = model.GetNumberOfScriptRuns( 0u, numberOfCharacters );
+
+ Vector<ScriptRun> scriptRuns;
+ scriptRuns.Reserve( numberOfScriptRuns );
+
+ ScriptRun* scriptRunsBuffer = scriptRuns.Begin();
+ model.GetScriptRuns( scriptRunsBuffer,
+ 0u,
+ numberOfCharacters );
+
+ // 4) Traverse the characters and validate/set the fonts.
+
+ // Get the caches.
+ FontId* defaultFontPerScriptCacheBuffer = mDefaultFontPerScriptCache.Begin();
+ ValidateFontsPerScript** validFontsPerScriptCacheBuffer = mValidFontsPerScriptCache.Begin();
+
+ // Stores the validated font runs.
+ Vector<FontRun> validatedFontRuns;
+ validatedFontRuns.Reserve( numberOfFontRuns );
+
+ // Initializes a validated font run.
+ FontRun currentFontRun;
+ currentFontRun.characterRun.characterIndex = 0u;
+ currentFontRun.characterRun.numberOfCharacters = 0u;
+ currentFontRun.fontId = 0u;
+ currentFontRun.isDefault = false;
+
+ // Get the font client.
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+ // Iterators of the font and script runs.
+ Vector<FontRun>::ConstIterator fontRunIt = fontRuns.Begin();
+ Vector<FontRun>::ConstIterator fontRunEndIt = fontRuns.End();
+ Vector<ScriptRun>::ConstIterator scriptRunIt = scriptRuns.Begin();
+ Vector<ScriptRun>::ConstIterator scriptRunEndIt = scriptRuns.End();
+
+ for( Length index = 0u; index < numberOfCharacters; ++index )
+ {
+ // Get the character.
+ const Character character = *( textBuffer + index );
+
+ // Get the font for the character.
+ FontId fontId = GetFontId( index,
+ fontRunIt,
+ fontRunEndIt );
+
+ // Get the script for the character.
+ Script script = GetScript( index,
+ scriptRunIt,
+ scriptRunEndIt );
+
+ if( TextAbstraction::UNKNOWN == script )
+ {
+ DALI_LOG_WARNING( "MultilanguageSupport::ValidateFonts. Unknown script!" );
+ script = TextAbstraction::LATIN;
+ }
+
+ // Whether the font being validated is a default one not set by the user.
+ const bool isDefault = ( 0u == fontId );
+
+ // The default font point size.
+ PointSize26Dot6 pointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+
+ if( !isDefault )
+ {
+ // Validate if the font set by the user supports the character.
+
+ // Check first in the caches.
+
+ // The user may have set the default font. Check it. Otherwise check in the valid fonts cache.
+ if( fontId != *( defaultFontPerScriptCacheBuffer + script ) )
+ {
+ // Check in the valid fonts cache.
+ ValidateFontsPerScript* validateFontsPerScript = *( validFontsPerScriptCacheBuffer + script );
+ if( NULL != validateFontsPerScript )
+ {
+ if( !validateFontsPerScript->FindValidFont( fontId ) )
+ {
+ // Use the font client to validate the font.
+ const GlyphIndex glyphIndex = fontClient.GetGlyphIndex( fontId, character );
+
+ if( 0u == glyphIndex )
+ {
+ // Get the point size of the current font. It will be used to get a default font id.
+ pointSize = fontClient.GetPointSize( fontId );
+
+ // The font is not valid. Set to zero and a default one will be set.
+ fontId = 0u;
+ }
+ else
+ {
+ // Add the font to the valid font cache.
+ validateFontsPerScript->mValidFonts.PushBack( fontId );
+ }
+ }
+ }
+ else
+ {
+ // Use the font client to validate the font.
+ const GlyphIndex glyphIndex = fontClient.GetGlyphIndex( fontId, character );
+
+ if( 0u == glyphIndex )
+ {
+ // Get the point size of the current font. It will be used to get a default font id.
+ pointSize = fontClient.GetPointSize( fontId );
+
+ // The font is not valid. Set to zero and a default one will be set.
+ fontId = 0u;
+ }
+ else
+ {
+ // Add the font to the valid font cache.
+ validateFontsPerScript = new ValidateFontsPerScript();
+ *( validFontsPerScriptCacheBuffer + script ) = validateFontsPerScript;
+
+ validateFontsPerScript->mValidFonts.PushBack( fontId );
+ }
+ }
+ }
+ }
+
+ // The font has not been validated. Find a default one.
+ if( 0u == fontId )
+ {
+ // The character has no font assigned. Get a default one from the cache
+ fontId = *( defaultFontPerScriptCacheBuffer + script );
+
+ // If the cache has not a default font, get one from the font client.
+ if( 0u == fontId )
+ {
+ // Find a default font.
+ fontId = fontClient.FindDefaultFont( character, pointSize );
+
+ // Cache the font.
+ *( defaultFontPerScriptCacheBuffer + script ) = fontId;
+ }
+ }
+
+ // The font is now validated.
+
+ if( ( fontId != currentFontRun.fontId ) ||
+ ( isDefault != currentFontRun.isDefault ) )
+ {
+ // Current run needs to be stored and a new one initialized.
+
+ if( 0u != currentFontRun.characterRun.numberOfCharacters )
+ {
+ // Store the font run.
+ validatedFontRuns.PushBack( currentFontRun );
+ }
+
+ // Initialize the new one.
+ currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters;
+ currentFontRun.characterRun.numberOfCharacters = 0u;
+ currentFontRun.fontId = fontId;
+ currentFontRun.isDefault = isDefault;
+ }
+
+ // Add one more character to the run.
+ ++currentFontRun.characterRun.numberOfCharacters;
+ }
+
+ if( 0u != currentFontRun.characterRun.numberOfCharacters )
+ {
+ // Store the last run.
+ validatedFontRuns.PushBack( currentFontRun );
+ }
+
+ // 5) Sets the validated font runs to the model.
+ model.SetFonts( validatedFontRuns.Begin(),
+ validatedFontRuns.Count() );
+}
+
+} // namespace Internal
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_IMPL_H__
+#define __DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/multi-language-support.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Stores valid font ids per script.
+ */
+struct ValidateFontsPerScript
+{
+ /**
+ * Default constructor.
+ */
+ ValidateFontsPerScript()
+ : mValidFonts()
+ {}
+
+ /**
+ * Default destructor.
+ */
+ ~ValidateFontsPerScript()
+ {}
+
+ /**
+ * @brief Whether the given @p fontId is in the vector of valid fonts.
+ *
+ * @param[in] fontId The font id.
+ *
+ * @return @e true if the font is in the vector of valid fonts.
+ */
+ bool FindValidFont( FontId fontId ) const;
+
+ Vector<FontId> mValidFonts;
+};
+
+/**
+ * @brief Multi-language support implementation. @see Text::MultilanguageSupport.
+ */
+class MultilanguageSupport : public BaseObject
+{
+public:
+
+ /**
+ * Constructor
+ */
+ MultilanguageSupport();
+
+ /**
+ * Destructor
+ *
+ * This is non-virtual since derived Handle types must not contain data or virtual methods.
+ */
+ ~MultilanguageSupport();
+
+ /**
+ * @copydoc Dali::MultilanguageSupport::Get()
+ */
+ static Text::MultilanguageSupport Get();
+
+ /**
+ * @copydoc Dali::MultilanguageSupport::SetScripts()
+ */
+ void SetScripts( LogicalModel& model );
+
+ /**
+ * @copydoc Dali::MultilanguageSupport::ValidateFonts()
+ */
+ void ValidateFonts( LogicalModel& model );
+
+private:
+ Vector<FontId> mDefaultFontPerScriptCache; ///< Caches the default font for a script.
+ Vector<ValidateFontsPerScript*> mValidFontsPerScriptCache; ///< Caches valid fonts for a script.
+};
+
+} // namespace Internal
+
+inline static Internal::MultilanguageSupport& GetImplementation( MultilanguageSupport& multilanguageSupport )
+{
+ DALI_ASSERT_ALWAYS( multilanguageSupport && "multi-language handle is empty" );
+ BaseObject& handle = multilanguageSupport.GetBaseObject();
+ return static_cast<Internal::MultilanguageSupport&>( handle );
+}
+
+inline static const Internal::MultilanguageSupport& GetImplementation( const MultilanguageSupport& multilanguageSupport )
+{
+ DALI_ASSERT_ALWAYS( multilanguageSupport && "multi-language handle is empty" );
+ const BaseObject& handle = multilanguageSupport.GetBaseObject();
+ return static_cast<const Internal::MultilanguageSupport&>( handle );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_IMPL_H__
namespace Toolkit
{
+const std::string TextLabel::TEXT_PROPERTY_NAME("text");
+const std::string TextLabel::MULTI_LINE_PROPERTY_NAME("multi-line");
+
TextLabel TextLabel::New()
{
return Internal::TextLabel::New();
public:
// Property indices
- static const Property::Index PROPERTY_TEXT; ///< name "text", type STRING
+ static const Property::Index PROPERTY_TEXT; ///< name "text", type STRING
+ static const Property::Index PROPERTY_MULTI_LINE; ///< name "multi-line", type BOOLEAN
// Property names
- static const std::string TEXT_PROPERTY_NAME; ///< Property, name "text", type STRING
+ static const std::string TEXT_PROPERTY_NAME; ///< Property, name "text", type STRING
+ static const std::string MULTI_LINE_PROPERTY_NAME; ///< Property, name "multi-line", type BOOLEAN
/**
* Create the TextLabel control.
$(public_api_base_src_dir)/text/character-set-conversion.cpp \
$(public_api_base_src_dir)/text/logical-model.cpp \
$(public_api_base_src_dir)/text/multi-language-support.cpp \
+ $(public_api_base_src_dir)/text/script.cpp \
$(public_api_base_src_dir)/text/segmentation.cpp \
$(public_api_base_src_dir)/text/text-controller.cpp \
$(public_api_base_src_dir)/text/text-view.cpp \
$(public_api_base_src_dir)/text/text-view-interface.cpp \
$(public_api_base_src_dir)/text/visual-model.cpp \
+ $(public_api_base_src_dir)/text/layouts/layout-engine.cpp \
$(public_api_base_src_dir)/text/rendering/text-renderer.cpp \
$(public_api_base_src_dir)/text/rendering/basic/text-basic-renderer.cpp \
$(public_api_base_src_dir)/text/rendering/shaders/text-basic-shader.cpp \
$(public_api_base_src_dir)/text/logical-model.h \
$(public_api_base_src_dir)/text/multi-language-support.h \
$(public_api_base_src_dir)/text/script.h \
+ $(public_api_base_src_dir)/text/script-run.h \
$(public_api_base_src_dir)/text/segmentation.h \
$(public_api_base_src_dir)/text/text-controller.h \
$(public_api_base_src_dir)/text/text-definitions.h \
$(public_api_base_src_dir)/text/text-view-interface.h \
$(public_api_base_src_dir)/text/visual-model.h
+public_api_base_text_layouts_header_files = \
+ $(public_api_base_src_dir)/text/layouts/layout-engine.h
+
public_api_base_text_rendering_header_files = \
$(public_api_base_src_dir)/text/rendering/text-renderer.h
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/text/layouts/layout-engine.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/logical-model.h>
+#include <dali-toolkit/public-api/text/visual-model.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct LayoutEngine::Impl
+{
+ Impl()
+ : mLayout( LayoutEngine::SINGLE_LINE_BOX )
+ {
+ mFontClient = TextAbstraction::FontClient::Get();
+ }
+
+ void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel )
+ {
+ // TODO Switch between different layouts
+
+ TextAbstraction::FontId fontId = mFontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 13*64 );
+
+ const Length characterCount = logicalModel.GetNumberOfCharacters();
+
+ Vector<GlyphInfo> glyphs;
+ glyphs.Reserve( characterCount );
+
+ Vector<CharacterIndex> characterIndices;
+ characterIndices.Reserve( characterCount );
+
+ std::vector<Length> charactersPerGlyph;
+ charactersPerGlyph.assign( characterCount, 1 );
+
+ for( unsigned int i=0; i<characterCount; ++i )
+ {
+ Character charcode;
+ logicalModel.GetText( i, &charcode, 1 );
+
+ // TODO - Perform shaping to get correct glyph indices
+ GlyphIndex glyphIndex = mFontClient.GetGlyphIndex( fontId, charcode );
+
+ glyphs.PushBack( GlyphInfo(fontId, glyphIndex) );
+ characterIndices.PushBack( 1 );
+ }
+
+ if( mFontClient.GetGlyphMetrics( &glyphs[0], glyphs.Size() ) )
+ {
+ visualModel.SetGlyphs( &glyphs[0],
+ &characterIndices[0],
+ &charactersPerGlyph[0],
+ characterCount );
+
+ UpdateGlyphPositions( boundingBox, visualModel );
+ }
+ }
+
+ void UpdateGlyphPositions( const Vector2& boundingBox, VisualModel& visualModel )
+ {
+ if( LayoutEngine::SINGLE_LINE_BOX == mLayout )
+ {
+ SingleLineLayout( boundingBox, visualModel );
+ }
+ else
+ {
+ MultiLineLayout( boundingBox, visualModel );
+ }
+ }
+
+ // TODO - Rewrite this to handle bidi
+ void SingleLineLayout( const Vector2& boundingBox, VisualModel& visualModel )
+ {
+ Length glyphCount = visualModel.GetNumberOfGlyphs();
+
+ std::vector<Vector2> glyphPositions;
+ glyphPositions.reserve( glyphCount );
+
+ if( glyphCount > 0 )
+ {
+ // FIXME Single font assumption
+ Text::FontMetrics fontMetrics;
+ GlyphInfo firstGlyph;
+ visualModel.GetGlyphs( 0, &firstGlyph, 1 );
+ mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
+
+ float penX( 0 );
+ float penY( fontMetrics.ascender ); // Move to baseline
+
+ for( unsigned int i=0; i<glyphCount; ++i )
+ {
+ GlyphInfo glyph;
+ visualModel.GetGlyphs( i, &glyph, 1 );
+
+ glyphPositions.push_back( Vector2( penX + glyph.xBearing,
+ penY - glyph.yBearing ) );
+
+ penX += glyph.advance;
+ }
+
+ visualModel.SetGlyphPositions( &glyphPositions[0], glyphCount );
+ }
+ }
+
+ // TODO - Rewrite this to handle bidi
+ void MultiLineLayout( const Vector2& boundingBox, VisualModel& visualModel )
+ {
+ Length glyphCount = visualModel.GetNumberOfGlyphs();
+
+ std::vector<Vector2> glyphPositions;
+ glyphPositions.reserve( glyphCount );
+
+ if( glyphCount > 0 )
+ {
+ // FIXME Single font assumption
+ Text::FontMetrics fontMetrics;
+ GlyphInfo firstGlyph;
+ visualModel.GetGlyphs( 0, &firstGlyph, 1 );
+ mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
+
+ float penX( 0 );
+ float penY( fontMetrics.ascender ); // Move to baseline
+
+ unsigned int i=0;
+ while( i < glyphCount )
+ {
+ // Skip initial whitespace
+ for( ; i<glyphCount; ++i )
+ {
+ GlyphInfo glyph;
+ visualModel.GetGlyphs( i, &glyph, 1 );
+
+ if( glyph.width > 0 &&
+ glyph.height > 0 )
+ {
+ break;
+ }
+ else
+ {
+ glyphPositions.push_back( Vector2( penX + glyph.xBearing,
+ penY - glyph.yBearing ) );
+ }
+ }
+
+ // Find last glyph for the next line
+ unsigned int endIndex = i;
+ float endPenX = penX;
+ unsigned int j=i;
+ for( ; j<glyphCount; ++j )
+ {
+ GlyphInfo glyph;
+ visualModel.GetGlyphs( j, &glyph, 1 );
+
+ endPenX += glyph.advance;
+
+ if( glyph.width <= 0 ||
+ glyph.height <= 0 )
+ {
+ // Potential line end found
+ endIndex = j;
+ }
+ else if( endPenX > boundingBox.width )
+ {
+ break;
+ }
+ }
+
+ // If end of text or no whitespace found
+ if( glyphCount == j ||
+ endIndex == i )
+ {
+ endIndex = j;
+ }
+
+ for( ; i<endIndex; ++i )
+ {
+ GlyphInfo glyph;
+ visualModel.GetGlyphs( i, &glyph, 1 );
+
+ glyphPositions.push_back( Vector2( penX + glyph.xBearing,
+ penY - glyph.yBearing ) );
+
+ penX += glyph.advance;
+ }
+
+ // Go to next line
+ penX = 0;
+ penY += fontMetrics.height;
+ }
+
+ visualModel.SetGlyphPositions( &glyphPositions[0], glyphCount );
+ }
+ }
+
+ unsigned int mLayout;
+
+ TextAbstraction::FontClient mFontClient;
+};
+
+LayoutEngine::LayoutEngine()
+: mImpl( NULL )
+{
+ mImpl = new LayoutEngine::Impl();
+}
+
+LayoutEngine::~LayoutEngine()
+{
+ delete mImpl;
+}
+
+void LayoutEngine::SetLayout( Layout layout )
+{
+ mImpl->mLayout = layout;
+}
+
+void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel )
+{
+ mImpl->UpdateVisualModel( boundingBox, logicalModel, visualModel );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H__
+#define __DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+struct Vector2;
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class LogicalModel;
+class VisualModel;
+
+/**
+ * @brief LayoutEngine is responsible for calculating the visual position of glyphs in layout.
+ */
+class LayoutEngine
+{
+public:
+
+ enum Layout
+ {
+ SINGLE_LINE_BOX,
+ MULTI_LINE_BOX
+ };
+
+ /**
+ * @brief Create a new instance of a LayoutEngine.
+ */
+ LayoutEngine();
+
+ /**
+ * @brief Virtual destructor.
+ */
+ ~LayoutEngine();
+
+ /**
+ * @brief Choose the required layout.
+ *
+ * @param[in] layout The required layout.
+ */
+ void SetLayout( Layout layout );
+
+ /**
+ * @brief Store the visual position of glyphs in the VisualModel.
+ *
+ * @param[in] boundingBox The size of the box containing the text.
+ * @param[in] logicalModel The logical model.
+ * @param[in] visualModel The visual model to update.
+ */
+ void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel );
+
+private:
+
+ // Undefined
+ LayoutEngine( const LayoutEngine& handle );
+
+ // Undefined
+ LayoutEngine& operator=( const LayoutEngine& handle );
+
+private:
+
+ struct Impl;
+ Impl* mImpl;
+};
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H__
// FILE HEADER
#include <dali-toolkit/public-api/text/multi-language-support.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/multi-language-support-impl.h>
+
namespace Dali
{
}
MultilanguageSupport::MultilanguageSupport( Internal::MultilanguageSupport* implementation )
+: BaseHandle( implementation )
{
}
MultilanguageSupport MultilanguageSupport::Get()
{
- return MultilanguageSupport();
+ return Internal::MultilanguageSupport::Get();
}
void MultilanguageSupport::SetScripts( LogicalModel& model )
{
+ GetImplementation( *this ).SetScripts( model );
}
void MultilanguageSupport::ValidateFonts( LogicalModel& model )
{
+ GetImplementation( *this ).ValidateFonts( model );
}
} // namespace Text
/**
* @brief This constructor is used by MultilanguageSupport::Get().
*
- * @param[in] implementation A pointer to the internal multilanguage support object.
+ * @param[in] implementation A pointer to the internal multi-language support object.
*/
explicit DALI_INTERNAL MultilanguageSupport( Internal::MultilanguageSupport* implementation );
*
* Any script info previously set is removed.
*
+ * Scripts are used to validate and set default fonts and to shape the text in further steps.
+ *
* @pre The @p model needs to have a text set.
*
* @param[in,out] model The text's logical model.
/**
* @brief Validates the character's font of the whole text.
*
- * It may update fonts set by the mark-up processor.
- * It sets default fonts based on the script to those characters without a font set.
+ * It may update fonts set by application developers.
+ *
+ * This method ensures all characters are going to be rendered using an appropriate font. Provided a valid font
+ * exists in the platform.
+ *
+ * For those characters with no font set, it sets a default one.
+ *
+ * If a font has been set by the application developer, this method checks if the font supports the character.
+ * If it doesn't, this method replaces it by a default one.
*
* @pre The @p model needs to have a text set.
* @pre The @p model needs to have the scripts set.
Script GetCharacterScript( Character character )
{
+ // Latin script:
+ // 0x0000 - 0x007f C0 Controls and Basic Latin
+ // 0x0080 - 0x00ff C1 Controls and Latin-1 Supplement
+ // 0x0100 - 0x017f Latin Extended-A
+ // 0x0180 - 0x024f Latin Extended-B
+ // 0x0250 - 0x02af IPA Extensions
+ // 0x02b0 - 0x02ff Spacing Modifier Letters
+ // 0x1d00 - 0x1d7f Phonetic Extensions
+ // 0x1d80 - 0x1dbf Phonetic Extensions Supplement
+ // 0x1e00 - 0x1eff Latin Extended Additional
+ // 0x2070 - 0x209f Superscripts and Subscripts
+ // 0x2100 - 0x214f Letterlike symbols
+ // 0x2150 - 0x218f Number Forms
+ // 0x2c60 - 0x2c7f Latin Extended-C
+ // 0xa720 - 0xa7ff Latin Extended-D
+ // 0xab30 - 0xab6f Latin Extended-E
+ // 0xfb00 - 0xfb4f Alphabetic Presentation Forms
+ // 0xff00 - 0xffef Halfwidth and Fullwidth Forms
+
+ // Brahmic scripts:
+ // 0x0900 - 0x097f Devanagari
+ // 0x0980 - 0x09ff Bengali
+ // 0x0a00 - 0x0a7f Gurmukhi
+ // 0x0a80 - 0x0aff Gujarati
+ // 0x0b00 - 0x0b7f Oriya
+ // 0x0b80 - 0x0bff Tamil
+ // 0x0c00 - 0x0c7f Telugu
+ // 0x0c80 - 0x0cff Kannada
+ // 0x0d00 - 0x0d7f Malayalam
+
+ // Sinhala script.
+ // 0x0d80 - 0x0dff Sinhala
+
+ // Arabic script.
+ // 0x0600 - 0x06ff Arabic
+ // 0x0750 - 0x077f Arabic Supplement
+ // 0x08A0 - 0x08ff Arabic Extended-A
+ // 0xfb50 - 0xfdff Arabic Presentation Forms-A
+ // 0xfe70 - 0xfeff Arabic Presentation Forms-B
+ // 0x1ee00 - 0x1eeff Arabic Mathematical Alphabetic Symbols
+
+ // CJK and Vietnamese script.
+ // 0x2E80 - 0x2eff CJK Radicals Supplement
+ // 0x3000 - 0x303f CJK Symbols and Punctuation
+ // 0x3200 - 0x32ff Enclosed CJK Letters and Months
+ // 0x3400 - 0x4dbf CJK Unified Ideographs Extension A
+ // 0x4e00 - 0x62ff CJK Unified Ideographs
+ // 0x6300 - 0x77ff CJK Unified Ideographs
+ // 0x7800 - 0x8cff CJK Unified Ideographs
+ // 0x8d00 - 0x9fff CJK Unified Ideographs
+ // 0x20000 - 0x215ff CJK Unified Ideographs Extension B
+ // 0x21600 - 0x230ff CJK Unified Ideographs Extension B
+ // 0x23100 - 0x245ff CJK Unified Ideographs Extension B
+ // 0x24600 - 0x260ff CJK Unified Ideographs Extension B
+ // 0x26100 - 0x275ff CJK Unified Ideographs Extension B
+ // 0x27600 - 0x290ff CJK Unified Ideographs Extension B
+ // 0x29100 - 0x2a6df CJK Unified Ideographs Extension B
+ // 2a700-2b73f. CJK Unified Ideographs Extension C
+ // 2b740-2b81f. CJK Unified Ideographs Extension D
+
+ // Hangul script
+ // 0x1100 - 0x11ff Hangul jamo
+ // 0x3130 - 0x318f Hangul Compatibility Jamo
+ // 0xa960 - 0xa97f Hangul Jamo Extended-A
+ // 0xac00 - 0xd7af Hangul Syllables
+ // 0xd7b0 - 0xd7ff Hangul Jamo Extended-B
+
+ // Khmer script
+ // 0x1780 - 0x17ff Khmer
+ // 0x19e0 - 0x19ff Khmer Symbols
+
+ // Lao script
+ // 0x0e80 - 0x0eff Lao
+
+ // Thai script
+ // 0x0e00 - 0x0e7f Thai
+
+ // Burmese script
+ // 0x1000 - 0x104f Myanmar
+
+
+ if( character <= 0x0cff )
+ {
+ if( character <= 0x09ff )
+ {
+ if( character <= 0x077f )
+ {
+ if( character <= 0x02ff )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0x0600 <= character ) && ( character <= 0x06ff ) )
+ {
+ return TextAbstraction::ARABIC;
+ }
+ if( ( 0x0750 <= character ) && ( character <= 0x077f ) )
+ {
+ return TextAbstraction::ARABIC;
+ }
+ }
+ else // > 0x077f
+ {
+ if( ( 0x08A0 <= character ) && ( character <= 0x08ff ) )
+ {
+ return TextAbstraction::ARABIC;
+ }
+ if( ( 0x0900 <= character ) && ( character <= 0x097f ) )
+ {
+ return TextAbstraction::DEVANAGARI;
+ }
+ if( ( 0x0980 <= character ) && ( character <= 0x09ff ) )
+ {
+ return TextAbstraction::BENGALI;
+ }
+ }
+ }
+ else // > 0x09ff
+ {
+ if( character <= 0x0b7f )
+ {
+ if( ( 0x0a00 <= character ) && ( character <= 0x0a7f ) )
+ {
+ return TextAbstraction::GURMUKHI;
+ }
+ if( ( 0x0a80 <= character ) && ( character <= 0x0aff ) )
+ {
+ return TextAbstraction::GUJARATI;
+ }
+ if( ( 0x0b00 <= character ) && ( character <= 0x0b7f ) )
+ {
+ return TextAbstraction::ORIYA;
+ }
+ }
+ else // > 0x0b7f
+ {
+ if( ( 0x0b80 <= character ) && ( character <= 0x0bff ) )
+ {
+ return TextAbstraction::TAMIL;
+ }
+ if( ( 0x0c00 <= character ) && ( character <= 0x0c7f ) )
+ {
+ return TextAbstraction::TELUGU;
+ }
+ if( ( 0x0c80 <= character ) && ( character <= 0x0cff ) )
+ {
+ return TextAbstraction::KANNADA;
+ }
+ }
+ }
+ }
+ else // > 0x0cff
+ {
+ if( character <= 0x2c7f )
+ {
+ if( character <= 0x1eff )
+ {
+ if( ( 0x0d00 <= character ) && ( character <= 0x0d7f ) )
+ {
+ return TextAbstraction::MALAYALAM;
+ }
+ if( ( 0x0d80 <= character ) && ( character <= 0x0dff ) )
+ {
+ return TextAbstraction::SINHALA;
+ }
+ if( ( 0x0e00 <= character ) && ( character <= 0x0e7f ) )
+ {
+ return TextAbstraction::THAI;
+ }
+ if( ( 0x0e80 <= character ) && ( character <= 0x0eff ) )
+ {
+ return TextAbstraction::LAO;
+ }
+ if( ( 0x1000 <= character ) && ( character <= 0x104f ) )
+ {
+ return TextAbstraction::BURMESE;
+ }
+ if( ( 0x1100 <= character ) && ( character <= 0x11ff ) )
+ {
+ return TextAbstraction::HANGUL;
+ }
+ if( ( 0x1780 <= character ) && ( character <= 0x17ff ) )
+ {
+ return TextAbstraction::KHMER;
+ }
+ if( ( 0x19e0 <= character ) && ( character <= 0x19ff ) )
+ {
+ return TextAbstraction::KHMER;
+ }
+ if( ( 0x1d00 <= character ) && ( character <= 0x1eff ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ }
+ else // > 0x1eff
+ {
+ if( ( 0x2070 <= character ) && ( character <= 0x209f ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0x2100 <= character ) && ( character <= 0x218f ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0x2c60 <= character ) && ( character <= 0x2c7f ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ }
+ }
+ else // > 0x2c7f
+ {
+ if( character <= 0xfdff )
+ {
+ if( ( 0x2e80 <= character ) && ( character <= 0x2eff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x3000 <= character ) && ( character <= 0x303f ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x3130 <= character ) && ( character <= 0x318f ) )
+ {
+ return TextAbstraction::HANGUL;
+ }
+ if( ( 0x3200 <= character ) && ( character <= 0x32ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x3400 <= character ) && ( character <= 0x4dbf ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x4e00 <= character ) && ( character <= 0x62ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x6300 <= character ) && ( character <= 0x77ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x7800 <= character ) && ( character <= 0x8cff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x8d00 <= character ) && ( character <= 0x9fff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0xa720 <= character ) && ( character <= 0xa7ff ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0xa960 <= character ) && ( character <= 0xa97f ) )
+ {
+ return TextAbstraction::HANGUL;
+ }
+ if( ( 0xab30 <= character ) && ( character <= 0xab6f ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0xac00 <= character ) && ( character <= 0xd7af ) )
+ {
+ return TextAbstraction::HANGUL;
+ }
+ if( ( 0xd7b0 <= character ) && ( character <= 0xd7ff ) )
+ {
+ return TextAbstraction::HANGUL;
+ }
+ if( ( 0xfb00 <= character ) && ( character <= 0xfb4f ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0xfb50 <= character ) && ( character <= 0xfdff ) )
+ {
+ return TextAbstraction::ARABIC;
+ }
+ }
+ else // > 0xfdff
+ {
+ if( ( 0xfe70 <= character ) && ( character <= 0xfeff ) )
+ {
+ return TextAbstraction::ARABIC;
+ }
+ if( ( 0xff00 <= character ) && ( character <= 0xffef ) )
+ {
+ return TextAbstraction::LATIN;
+ }
+ if( ( 0x1ee00 <= character ) && ( character <= 0x1eeff ) )
+ {
+ return TextAbstraction::ARABIC;
+ }
+ if( ( 0x20000 <= character ) && ( character <= 0x215ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x21600 <= character ) && ( character <= 0x230ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x23100 <= character ) && ( character <= 0x245ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x24600 <= character ) && ( character <= 0x260ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x26100 <= character ) && ( character <= 0x275ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x27600 <= character ) && ( character <= 0x290ff ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x29100 <= character ) && ( character <= 0x2a6df ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x2a700 <= character ) && ( character <= 0x2b73f ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ if( ( 0x2b740 <= character ) && ( character <= 0x2b81f ) )
+ {
+ return TextAbstraction::CJK;
+ }
+ }
+ }
+ }
+
return TextAbstraction::UNKNOWN;
}
// CLASS HEADER
#include <dali-toolkit/public-api/text/text-controller.h>
+// EXTERNAL INCLUDES
+#include <dali/public-api/text-abstraction/font-client.h>
+
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/text/character-set-conversion.h>
+#include <dali-toolkit/public-api/text/layouts/layout-engine.h>
#include <dali-toolkit/public-api/text/logical-model.h>
#include <dali-toolkit/public-api/text/text-view.h>
#include <dali-toolkit/public-api/text/visual-model.h>
struct Controller::Impl
{
Impl()
+ : mNewTextArrived( false )
{
mLogicalModel = LogicalModel::New();
mVisualModel = VisualModel::New();
mFontClient = TextAbstraction::FontClient::Get();
}
+ std::string mNewText;
+ bool mNewTextArrived;
+
LogicalModelPtr mLogicalModel;
VisualModelPtr mVisualModel;
View mView;
+ LayoutEngine mLayoutEngine;
+
TextAbstraction::FontClient mFontClient;
};
void Controller::SetText( const std::string& text )
{
- // Convert text into UTF-32
- Vector<Character> utf32Characters;
- utf32Characters.Resize( text.size() );
+ // Keep until size negotiation
+ mImpl->mNewText = text;
+ mImpl->mNewTextArrived = true;
+}
+
+bool Controller::Relayout( const Vector2& size )
+{
+ bool viewUpdated( false );
+
+ if( mImpl->mNewTextArrived )
+ {
+ std::string& text = mImpl->mNewText;
+
+ // Convert text into UTF-32
+ Vector<Character> utf32Characters;
+ utf32Characters.Resize( text.size() );
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+
+ Length characterCount = Utf8ToUtf32( utf8, text.size(), &utf32Characters[0] );
- // This is a bit horrible but std::string returns a (signed) char*
- const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+ // Manipulate the logical model
+ mImpl->mLogicalModel->SetText( &utf32Characters[0], characterCount );
- Length characterCount = Utf8ToUtf32( utf8, text.size(), &utf32Characters[0] );
+ // Update the visual model
+ mImpl->mLayoutEngine.UpdateVisualModel( size, *mImpl->mLogicalModel, *mImpl->mVisualModel );
- // Manipulate the logical model
- mImpl->mLogicalModel->SetText( &utf32Characters[0], characterCount );
+ // Discard temporary text
+ mImpl->mNewTextArrived = false;
+ text.clear();
- UpdateVisualModel();
+ viewUpdated = true;
+ }
+
+ return viewUpdated;
}
View& Controller::GetView()
return mImpl->mView;
}
+LayoutEngine& Controller::GetLayoutEngine()
+{
+ return mImpl->mLayoutEngine;
+}
+
Controller::~Controller()
{
delete mImpl;
mImpl = new Controller::Impl();
}
-// TODO - Move this with LayoutEngine
-void Controller::UpdateVisualModel()
-{
- if( mImpl->mLogicalModel &&
- mImpl->mVisualModel )
- {
- const LogicalModel& logicalModel = *(mImpl->mLogicalModel);
- VisualModel& visualModel = *(mImpl->mVisualModel);
-
- TextAbstraction::FontId fontId = mImpl->mFontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 13*64 );
-
- const Length characterCount = logicalModel.GetNumberOfCharacters();
-
- Vector<GlyphInfo> glyphs;
- glyphs.Reserve( characterCount );
-
- Vector<CharacterIndex> characterIndices;
- characterIndices.Reserve( characterCount );
-
- std::vector<Length> charactersPerGlyph;
- charactersPerGlyph.assign( characterCount, 1 );
-
- for( unsigned int i=0; i<characterCount; ++i )
- {
- Character charcode;
- logicalModel.GetText( i, &charcode, 1 );
-
- // TODO - Perform shaping to get correct glyph indices
- GlyphIndex glyphIndex = mImpl->mFontClient.GetGlyphIndex( fontId, charcode );
-
- glyphs.PushBack( GlyphInfo(fontId, glyphIndex) );
- characterIndices.PushBack( 1 );
- }
-
- if( mImpl->mFontClient.GetGlyphMetrics( &glyphs[0], glyphs.Size() ) )
- {
- visualModel.SetGlyphs( &glyphs[0],
- &characterIndices[0],
- &charactersPerGlyph[0],
- characterCount );
-
- UpdateVisualPositions();
- }
- }
-}
-
-// TODO - Move this with LayoutEngine
-void Controller::UpdateVisualPositions()
-{
- if( mImpl->mVisualModel )
- {
- VisualModel& visualModel = *(mImpl->mVisualModel);
-
- Length glyphCount = visualModel.GetNumberOfGlyphs();
-
- std::vector<Vector2> glyphPositions;
- glyphPositions.reserve( glyphCount );
-
- if( glyphCount > 0 )
- {
- // FIXME Single font assumption
- Text::FontMetrics fontMetrics;
- GlyphInfo firstGlyph;
- visualModel.GetGlyphs( 0, &firstGlyph, 1 );
- mImpl->mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
-
- float penX( 0 );
- float penY( fontMetrics.ascender ); // Move to baseline
-
- for( unsigned int i=0; i<glyphCount; ++i )
- {
- GlyphInfo glyph;
- visualModel.GetGlyphs( i, &glyph, 1 );
-
- glyphPositions.push_back( Vector2( penX + glyph.xBearing,
- penY - glyph.yBearing ) );
-
- penX += glyph.advance;
- }
-
- visualModel.SetGlyphPositions( &glyphPositions[0], glyphCount );
- }
- }
-}
-
} // namespace Text
} // namespace Toolkit
{
class Controller;
+class LayoutEngine;
+
typedef IntrusivePtr<Controller> ControllerPtr;
/**
*/
static ControllerPtr New();
- // TODO - Layouting options e.g. single vs multi-line
-
/**
* @brief Replaces any text previously set.
*
void SetText( const std::string& text );
/**
+ * @brief Triggers a relayout which updates View (if necessary).
+ *
+ * @note UI Controls are expected to minimize calls to this method e.g. call once after size negotiation.
+ * @param[in] size A the size of a bounding box to layout text within.
+ * @return True if the View was updated.
+ */
+ bool Relayout( const Vector2& size );
+
+ /**
+ * @brief Return the layout engine.
+ *
+ * @return A reference to the layout engine.
+ */
+ LayoutEngine& GetLayoutEngine();
+
+ /**
* @brief Return a view of the text.
*
- * @return An interface to the view.
+ * @return A reference to the view.
*/
View& GetView();
Controller();
/**
- * TODO - Move these with LayoutEngine
+ * @brief Populates the visual model.
*/
void UpdateVisualModel();
- void UpdateVisualPositions();
// Undefined
Controller( const Controller& handle );
publicapibasetableviewdir = $(publicapibasedir)/controls/table-view
publicapibasetextcontrolsdir = $(publicapibasedir)/controls/text-controls
publicapibasetextdir = $(publicapibasedir)/text
+publicapibasetextlayoutsdir = $(publicapibasedir)/text/layouts
publicapibasetextrenderingdir = $(publicapibasedir)/text/rendering
publicapibasetextrenderingbasicdir = $(publicapibasedir)/text/rendering/basic
publicapibasetextrenderingshadersdir = $(publicapibasedir)/text/rendering/shaders
publicapibasetableview_HEADERS = $(public_api_base_table_view_header_files)
publicapibasetextcontrols_HEADERS = $(public_api_base_text_controls_header_files)
publicapibasetext_HEADERS = $(public_api_base_text_header_files)
+publicapibasetextlayouts_HEADERS = $(public_api_base_text_layouts_header_files)
publicapibasetextrendering_HEADERS = $(public_api_base_text_rendering_header_files)
publicapibasetextrenderingbasic_HEADERS = $(public_api_base_text_rendering_basic_header_files)
publicapibasetextrenderingshaders_HEADERS = $(public_api_base_text_rendering_shaders_header_files)
#include <dali-toolkit/public-api/text/character-set-conversion.h>
#include <dali-toolkit/public-api/text/font-run.h>
#include <dali-toolkit/public-api/text/logical-model.h>
+#include <dali-toolkit/public-api/text/script.h>
#include <dali-toolkit/public-api/text/segmentation.h>
#include <dali-toolkit/public-api/text/multi-language-support.h>
-#include <dali-toolkit/public-api/text/script.h>
#include <dali-toolkit/public-api/text/text-controller.h>
#include <dali-toolkit/public-api/text/text-definitions.h>
#include <dali-toolkit/public-api/text/text-view.h>
#include <dali-toolkit/public-api/text/text-view-interface.h>
#include <dali-toolkit/public-api/text/visual-model.h>
+#include <dali-toolkit/public-api/text/layouts/layout-engine.h>
#include <dali-toolkit/public-api/text/rendering/text-renderer.h>
#include <dali-toolkit/public-api/text/rendering/basic/text-basic-renderer.h>
#include <dali-toolkit/public-api/text/rendering/shaders/text-basic-shader.h>