utc-Dali-Visuals-internal.cpp
utc-Dali-VisualModel.cpp
utc-Dali-VisualUrl.cpp
+ utc-Dali-Text-Hyphen-Wrapping.cpp
)
IF(ELDBUS_AVAILABLE)
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
namespace Dali
{
Size& layoutSize,
ModelPtr& textModel,
MetricsPtr& metrics,
- bool markupProcessorEnabled )
+ bool markupProcessorEnabled,
+ LineWrap::Mode wrapMode )
{
textModel = Model::New(); ///< Pointer to the text's model.
LogicalModelPtr logicalModel = textModel->mLogicalModel;
return;
}
+ textModel->mLineWrapMode = wrapMode;
+
+ if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+ {
+ CharacterIndex end = characterCount;
+ LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ for(CharacterIndex index = 0; index < end; index++)
+ {
+ CharacterIndex wordEnd = index;
+ while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+ {
+ wordEnd++;
+ }
+
+ if((wordEnd + 1) == end) // add last char
+ {
+ wordEnd++;
+ }
+
+ Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+ for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+ {
+ if(hyphens[i])
+ {
+ *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+ }
+ }
+
+ index = wordEnd;
+ }
+ }
+
// 3) Set the script info.
MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
// Set the layout parameters.
textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
- textModel->mLineWrapMode = LineWrap::WORD;
textModel->mIgnoreSpacesAfterText = true;
textModel->mMatchSystemLanguageDirection = false;
Layout::Parameters layoutParameters( textArea,
#define DALI_TOOLKIT_TEXT_UTILS_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
Size& layoutSize,
ModelPtr& textModel,
MetricsPtr& metrics,
- bool markupProcessorEnabled );
+ bool markupProcessorEnabled,
+ LineWrap::Mode wrapMode );
/**
* @brief Configures the text @p controller similarly to the one configured by the text-label.
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- data.markupProcessorEnabled );
+ data.markupProcessorEnabled,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
--- /dev/null
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+
+namespace
+{
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+struct LayoutTextData
+{
+ std::string text;
+ Size textArea;
+ unsigned int numberOfFonts;
+ FontDescriptionRun *fontDescriptions;
+ unsigned int numberOfLines;
+ LineRun* lines;
+ Layout::Engine::Type layout;
+ unsigned int startIndex;
+ unsigned int numberOfGlyphs;
+ Text::LineWrap::Mode wrapMode;
+};
+
+void Print( const LineRun& line )
+{
+ std::cout << " glyph run, index : " << line.glyphRun.glyphIndex << ", num glyphs : " << line.glyphRun.numberOfGlyphs << std::endl;
+ std::cout << " character run, index : " << line.characterRun.characterIndex << ", num chars : " << line.characterRun.numberOfCharacters << std::endl;
+}
+
+bool LayoutTextTest( const LayoutTextData& data )
+{
+ // Load some fonts.
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.SetDpi( 96u, 96u );
+
+ char* pathNamePtr = get_current_dir_name();
+ const std::string pathName( pathNamePtr );
+ free( pathNamePtr );
+
+ fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+
+ // 1) Create the model.
+ ModelPtr textModel;
+ MetricsPtr metrics;
+ Size layoutSize;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+ if( 0u != data.numberOfFonts )
+ {
+ fontDescriptionRuns.Insert( fontDescriptionRuns.End(),
+ data.fontDescriptions,
+ data.fontDescriptions + data.numberOfFonts );
+ }
+
+ LayoutOptions options;
+ options.align = false;
+ CreateTextModel( data.text,
+ data.textArea,
+ fontDescriptionRuns,
+ options,
+ layoutSize,
+ textModel,
+ metrics,
+ false,
+ data.wrapMode );
+
+ Vector<LineRun>& lines = textModel->mVisualModel->mLines;
+
+ // 4) Compare the results.
+
+ if( lines.Count() != data.numberOfLines )
+ {
+ std::cout << " Different number of lines : " << lines.Count() << ", expected : " << data.numberOfLines << std::endl;
+ return false;
+ }
+
+ for( unsigned int index = 0u; index < data.numberOfLines; ++index )
+ {
+ const LineRun& line = *( lines.Begin() + index );
+ const LineRun& expectedLine = *( data.lines + index );
+
+ if( line.characterRun.characterIndex != expectedLine.characterRun.characterIndex )
+ {
+ std::cout << " Different line info for line : " << index << std::endl;
+ Print( line );
+ std::cout << " expected" << std::endl;
+ Print( expectedLine );
+ return false;
+ }
+ if( line.characterRun.numberOfCharacters != expectedLine.characterRun.numberOfCharacters )
+ {
+ std::cout << " Different line info for line : " << index << std::endl;
+ Print( line );
+ std::cout << " expected" << std::endl;
+ Print( expectedLine );
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+
+int UtcDaliTextHyphenWrapping(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextHyphenWrapping");
+
+ // Layout some lines of left to right text.
+
+ const std::string fontFamily( "TizenSans" );
+
+ // Set a known font description
+ FontDescriptionRun fontDescriptionRun1;
+ fontDescriptionRun1.characterRun.characterIndex = 0u;
+ fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
+ fontDescriptionRun1.familyLength = fontFamily.size();
+ fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+ memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+ fontDescriptionRun1.familyDefined = true;
+ fontDescriptionRun1.weightDefined = false;
+ fontDescriptionRun1.widthDefined = false;
+ fontDescriptionRun1.slantDefined = false;
+ fontDescriptionRun1.sizeDefined = false;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+ fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+ Size textArea(65.0f, 200.f);
+
+ LineRun line1 =
+ {
+ { 0u, 5u },
+ { 0u, 5u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+ LineRun line2 =
+ {
+ { 5u, 8u },
+ { 5u, 8u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+
+ Vector<LineRun> lines;
+ lines.PushBack( line1 );
+ lines.PushBack( line2 );
+
+ LayoutTextData data =
+ {
+ "Hi Experiment",
+ textArea,
+ 1u,
+ fontDescriptionRuns.Begin(),
+ 2u,
+ lines.Begin(),
+ Layout::Engine::MULTI_LINE_BOX,
+ 0u,
+ 13u,
+ (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION
+ };
+
+ if( !LayoutTextTest( data ) )
+ {
+ tet_result(TET_FAIL);
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
+
+int UtcDaliTextMixedWrapping(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextMixedWrapping");
+
+ // Layout some lines of left to right text.
+
+ const std::string fontFamily( "DejaVuSans" );
+
+ // Set a known font description
+ FontDescriptionRun fontDescriptionRun1;
+ fontDescriptionRun1.characterRun.characterIndex = 0u;
+ fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
+ fontDescriptionRun1.familyLength = fontFamily.size();
+ fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+ memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+ fontDescriptionRun1.familyDefined = true;
+ fontDescriptionRun1.weightDefined = false;
+ fontDescriptionRun1.widthDefined = false;
+ fontDescriptionRun1.slantDefined = false;
+ fontDescriptionRun1.sizeDefined = false;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+ fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+ Size textArea(72.0f, 200.f);
+
+ LineRun line1 =
+ {
+ { 0u, 3u },
+ { 0u, 3u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+ LineRun line2 =
+ {
+ { 3u, 6u },
+ { 3u, 6u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+ LineRun line3 =
+ {
+ { 9u, 4u },
+ { 9u, 4u },
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ 0.f,
+ false,
+ false
+ };
+
+ Vector<LineRun> lines;
+ lines.PushBack( line1 );
+ lines.PushBack( line2 );
+ lines.PushBack( line3 );
+
+ LayoutTextData data =
+ {
+ "Hi Experiment",
+ textArea,
+ 1u,
+ fontDescriptionRuns.Begin(),
+ 3u,
+ lines.Begin(),
+ Layout::Engine::MULTI_LINE_BOX,
+ 0u,
+ 13u,
+ (Text::LineWrap::Mode)DevelText::LineWrap::MIXED
+ };
+
+ if( !LayoutTextTest( data ) )
+ {
+ tet_result(TET_FAIL);
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
\ No newline at end of file
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
layoutSize,
textModel,
metrics,
- false );
+ false,
+ LineWrap::WORD );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
#include <dali-toolkit/devel-api/text/rendering-backend.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
using namespace Dali;
using namespace Toolkit;
}
END_TEST;
+}
+
+int UtcDaliTextEditorHyphenWrapMode(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextEditorHyphenWrapMode ");
+
+ int lineCount =0;
+ TextEditor textEditor = TextEditor::New();
+
+ textEditor.SetProperty( Actor::Property::SIZE, Vector2( 150.0f, 300.f ) );
+
+ application.GetScene().Add( textEditor );
+ application.SendNotification();
+ application.Render();
+
+ textEditor.SetProperty( TextEditor::Property::TEXT, "Hi Experimen" );
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, DevelText::LineWrap::HYPHENATION);
+ DALI_TEST_EQUALS( textEditor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::HYPHENATION ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi Exp-
+ erimen
+ */
+ DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+ textEditor.SetProperty( TextEditor::Property::TEXT, "Hi Experimen" );
+ textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, DevelText::LineWrap::MIXED);
+ DALI_TEST_EQUALS( textEditor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::MIXED ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi
+ Experi-
+ men
+ */
+ DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+ END_TEST;
}
\ No newline at end of file
DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliTextLabelHyphenWrapMode(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliTextLabelHyphenWrapMode ");
+
+ int lineCount =0;
+ TextLabel label = TextLabel::New();
+ label.SetProperty( Actor::Property::SIZE, Vector2( 150.0f, 300.f ));
+ label.SetProperty( TextLabel::Property::POINT_SIZE, 12.f );
+ label.SetProperty( TextLabel::Property::MULTI_LINE, true);
+ application.GetScene().Add( label );
+ application.SendNotification();
+ application.Render();
+
+ label.SetProperty( TextLabel::Property::TEXT, "Hi Experimen" );
+ label.SetProperty(TextLabel::Property::LINE_WRAP_MODE,DevelText::LineWrap::HYPHENATION);
+ DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::HYPHENATION ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi Exp-
+ erimen
+ */
+ DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+ label.SetProperty( TextLabel::Property::TEXT, "Hi Experimen" );
+ label.SetProperty(TextLabel::Property::LINE_WRAP_MODE,DevelText::LineWrap::MIXED);
+ DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::MIXED ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ lineCount = label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+ /*
+ text will be :
+ Hi
+ Experi-
+ men
+ */
+ DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+ END_TEST;
+}
#define DALI_TOOLKIT_TEXT_ENUMERATIONS_DEVEL_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
};
} // namespace VerticalLineAlignment
+namespace LineWrap
+{
+enum Mode
+{
+ WORD,
+ CHARACTER,
+ HYPHENATION, // HYPHENATION mode will add hyphen and move part of the word to the next line.
+ MIXED // MIXEd mode will apply WORD mode, if failed try HYPHENATION mode, if failed try CHARACTER.
+};
+
+} // namespace LineWrap
} // namespace DevelText
// Resize the vector of positions to have the same size than the vector of glyphs.
rendererParameters.positions.Resize(numberOfGlyphs);
- textModel->mLineWrapMode = LineWrap::WORD;
+ textModel->mLineWrapMode = Text::LineWrap::WORD;
textModel->mIgnoreSpacesAfterText = false;
textModel->mMatchSystemLanguageDirection = false;
Text::Layout::Parameters layoutParameters(internalDataModel.textLayoutArea,
${toolkit_src_dir}/text/property-string-parser.cpp
${toolkit_src_dir}/text/segmentation.cpp
${toolkit_src_dir}/text/shaper.cpp
+ ${toolkit_src_dir}/text/hyphenator.cpp
${toolkit_src_dir}/text/text-enumerations-impl.cpp
${toolkit_src_dir}/text/text-controller.cpp
${toolkit_src_dir}/text/text-controller-event-handler.cpp
--- /dev/null
+/*
+ * Copyright (c) 2021 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/hyphenator.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/hyphenation.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+
+#include <cstring> // for strcmp
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+const char* UTF8 = "UTF-8";
+
+Vector<bool> GetWordHyphens(const Character* word,
+ Length wordSize,
+ const char* lang)
+{
+ Vector<bool> hyphens;
+
+ if(0u == wordSize || word == nullptr)
+ {
+ // Nothing to do if there are no characters.
+ return hyphens;
+ }
+
+ TextAbstraction::Hyphenation hyphenation = TextAbstraction::Hyphenation::Get();
+
+ // first get the needed encoding
+ std::string text;
+ if(strcmp(hyphenation.GetDictionaryEncoding(lang), UTF8) == 0)
+ {
+ Utf32ToUtf8(word, wordSize, text);
+ }
+ else
+ {
+ text = std::string((char*)word, (size_t)(wordSize * sizeof(Character)));
+ }
+
+ return hyphenation.GetWordHyphens(text.c_str(), (int)text.length(), lang);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_TEXT_HYPHENATOR_H
+#define DALI_TOOLKIT_TEXT_HYPHENATOR_H
+
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * Gets a vector booleans that indicates possible hyphen locations.
+ *
+ * @param[in] word the word to get possible hyphens for.
+ * @param[in] wordSize the word size in bytes.
+ * @param[in] lang the language for the word
+ *
+ * @return vector of boolean, true if possible to hyphenate at this character position.
+ */
+Vector<bool> GetWordHyphens(const Character* word,
+ Length wordSize,
+ const char* lang);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_HYPHENATOR_H
Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
#endif
-const float MAX_FLOAT = std::numeric_limits<float>::max();
-const CharacterDirection LTR = false;
-const CharacterDirection RTL = !LTR;
-const float LINE_SPACING = 0.f;
-const float MIN_LINE_SIZE = 0.f;
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+const CharacterDirection LTR = false;
+const CharacterDirection RTL = !LTR;
+const float LINE_SPACING = 0.f;
+const float MIN_LINE_SIZE = 0.f;
+const Character HYPHEN_UNICODE = 0x002D;
inline bool isEmptyLineAtLast(const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line)
{
const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
const bool isMultiline = mLayout == MULTI_LINE_BOX;
- const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD;
+ const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD ||
+ (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED);
+ const bool isHyphenMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION;
+ const bool isMixedMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED;
// The last glyph to be laid-out.
const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
FontId lastFontId = glyphMetrics.fontId;
UpdateLineHeight(glyphMetrics, tmpLineLayout);
- bool oneWordLaidOut = false;
+ bool oneWordLaidOut = false;
+ bool oneHyphenLaidOut = false;
+ GlyphIndex hyphenIndex = 0;
+ GlyphInfo hyphenGlyph;
for(GlyphIndex glyphIndex = lineLayout.glyphIndex;
glyphIndex < lastGlyphOfParagraphPlusOne;)
(tmpLineLayout.length > parameters.boundingBox.width))
{
// Current word does not fit in the box's width.
- if(!oneWordLaidOut || completelyFill)
+ if(((oneHyphenLaidOut && isHyphenMode) ||
+ (!oneWordLaidOut && isMixedMode && oneHyphenLaidOut)) &&
+ !completelyFill)
+ {
+ parameters.textModel->mVisualModel->mHyphen.glyph.PushBack(hyphenGlyph);
+ parameters.textModel->mVisualModel->mHyphen.index.PushBack(hyphenIndex + 1);
+ }
+
+ if((!oneWordLaidOut && !oneHyphenLaidOut) || completelyFill)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " Break the word by character\n");
(TextAbstraction::LINE_MUST_BREAK == lineBreakInfo))
{
LineLayout currentLineLayout = lineLayout;
-
+ oneHyphenLaidOut = false;
// Must break the line. Update the line layout and return.
MergeLineLayout(lineLayout, tmpLineLayout);
if(isMultiline &&
(TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo))
{
- oneWordLaidOut = isWordLaidOut;
+ oneHyphenLaidOut = false;
+ oneWordLaidOut = isWordLaidOut;
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " One word laid-out\n");
// Current glyph is the last one of the current word.
tmpLineLayout.Clear();
}
+ if(isMultiline &&
+ ((isHyphenMode || (!oneWordLaidOut && isMixedMode))) &&
+ (TextAbstraction::LINE_HYPHENATION_BREAK == lineBreakInfo))
+ {
+ hyphenGlyph = GlyphInfo();
+ hyphenGlyph.fontId = glyphsBuffer[glyphIndex].fontId;
+
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ hyphenGlyph.index = fontClient.GetGlyphIndex(hyphenGlyph.fontId, HYPHEN_UNICODE);
+
+ mMetrics->GetGlyphMetrics(&hyphenGlyph, 1);
+
+ if((tmpLineLayout.length + hyphenGlyph.width) <= parameters.boundingBox.width)
+ {
+ hyphenIndex = glyphIndex;
+ oneHyphenLaidOut = true;
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, " One hyphen laid-out\n");
+
+ // Current glyph is the last one of the current word hyphen.
+ // Add the temporal layout to the current one.
+ MergeLineLayout(lineLayout, tmpLineLayout);
+
+ tmpLineLayout.Clear();
+ }
+ }
+
glyphIndex += numberOfGLyphsInGroup;
}
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
DALI_LOG_INFO(gLogFilter, Debug::Verbose, " box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height);
+ layoutParameters.textModel->mVisualModel->mHyphen.glyph.Clear();
+ layoutParameters.textModel->mVisualModel->mHyphen.index.Clear();
+
Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
if(0u == layoutParameters.numberOfGlyphs)
if(ellipsis)
{
+ //clear hyphen from ellipsis line
+ const Length* hyphenIndices = layoutParameters.textModel->mVisualModel->mHyphen.index.Begin();
+ Length hyphensCount = layoutParameters.textModel->mVisualModel->mHyphen.glyph.Size();
+
+ while(hyphenIndices && hyphensCount > 0 && hyphenIndices[hyphensCount - 1] >= layout.glyphIndex)
+ {
+ layoutParameters.textModel->mVisualModel->mHyphen.index.Remove(layoutParameters.textModel->mVisualModel->mHyphen.index.Begin() + hyphensCount - 1);
+ layoutParameters.textModel->mVisualModel->mHyphen.glyph.Remove(layoutParameters.textModel->mVisualModel->mHyphen.glyph.Begin() + hyphensCount - 1);
+ hyphensCount--;
+ }
+
// No more lines to layout.
break;
}
Vector<Extent> extents;
mDepth = depth;
- const Vector2& textSize(view.GetLayoutSize());
- const Vector2 halfTextSize(textSize * 0.5f);
- const Vector2& shadowOffset(view.GetShadowOffset());
- const Vector4& shadowColor(view.GetShadowColor());
- const bool underlineEnabled = view.IsUnderlineEnabled();
- const Vector4& underlineColor(view.GetUnderlineColor());
- const float underlineHeight = view.GetUnderlineHeight();
- const uint16_t outlineWidth = view.GetOutlineWidth();
- const Vector4& outlineColor(view.GetOutlineColor());
- const bool isOutline = 0u != outlineWidth;
+ const Vector2& textSize(view.GetLayoutSize());
+ const Vector2 halfTextSize(textSize * 0.5f);
+ const Vector2& shadowOffset(view.GetShadowOffset());
+ const Vector4& shadowColor(view.GetShadowColor());
+ const bool underlineEnabled = view.IsUnderlineEnabled();
+ const Vector4& underlineColor(view.GetUnderlineColor());
+ const float underlineHeight = view.GetUnderlineHeight();
+ const uint16_t outlineWidth = view.GetOutlineWidth();
+ const Vector4& outlineColor(view.GetOutlineColor());
+ const bool isOutline = 0u != outlineWidth;
+ const GlyphInfo* hyphens = view.GetHyphens();
+ const Length* hyphenIndices = view.GetHyphenIndices();
+ const Length hyphensCount = view.GetHyphensCount();
const bool useDefaultColor = (NULL == colorsBuffer);
const GlyphInfo* const glyphsBuffer = glyphs.Begin();
const Vector2* const positionsBuffer = positions.Begin();
const Vector2 lineOffsetPosition(minLineOffset, 0.f);
+ uint32_t hyphenIndex = 0;
//For septated underlined chunks. (this is for Markup case)
uint32_t underlineChunkId = 0u; // give id for each chunk.
for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
{
- const GlyphInfo& glyph = *(glyphsBuffer + i);
- const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
- thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined;
+ GlyphInfo glyph;
+ bool addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && (i == hyphenIndices[hyphenIndex]));
+ if(addHyphen && hyphens)
+ {
+ glyph = hyphens[hyphenIndex];
+ i--;
+ }
+ else
+ {
+ glyph = *(glyphsBuffer + i);
+ }
+
+ const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
+ thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined;
// No operation for white space
if(glyph.width && glyph.height)
}
// Move the origin (0,0) of the mesh to the center of the actor
- const Vector2& temp = *(positionsBuffer + i);
- const Vector2 position = Vector2(roundf(temp.x), temp.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
+ Vector2 position = *(positionsBuffer + i);
+
+ if(addHyphen)
+ {
+ GlyphInfo tempInfo = *(glyphsBuffer + i);
+ position.x = position.x + tempInfo.advance - tempInfo.xBearing + glyph.xBearing;
+ position.y += tempInfo.yBearing - glyph.yBearing;
+ }
+
+ position = Vector2(roundf(position.x), position.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
if(0u != slot.mImageId) // invalid slot id, glyph has failed to be added to atlas
{
//Keep status of underlined for previous glyph to check consecutive indices
isPreUnderlined = isGlyphUnderlined;
}
+
+ if(addHyphen)
+ {
+ hyphenIndex++;
+ }
} // glyphs
// Now remove references for the old text
const Vector2* const positionBuffer = mModel->GetLayout();
const Vector4* const colorsBuffer = mModel->GetColors();
const ColorIndex* const colorIndexBuffer = mModel->GetColorIndices();
+ const GlyphInfo* hyphens = mModel->GetHyphens();
+ const Length* hyphenIndices = mModel->GetHyphenIndices();
+ const Length hyphensCount = mModel->GetHyphensCount();
// Whether to use the default color.
const bool useDefaultColor = (NULL == colorsBuffer);
}
// Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
- TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ Length hyphenIndex = 0;
// Traverses the lines of the text.
for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
float lineExtentLeft = bufferWidth;
float lineExtentRight = 0.0f;
float baseline = 0.0f;
+ bool addHyphen = false;
// Traverses the glyphs of the line.
const GlyphIndex endGlyphIndex = std::min(numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs);
}
// Retrieve the glyph's info.
- const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
+ const GlyphInfo* glyphInfo;
+
+ if(addHyphen && hyphens)
+ {
+ glyphInfo = hyphens + hyphenIndex;
+ hyphenIndex++;
+ }
+ else
+ {
+ glyphInfo = glyphsBuffer + glyphIndex;
+ }
if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
(glyphInfo->height < Math::MACHINE_EPSILON_1000))
} // underline
// Retrieves the glyph's position.
- const Vector2* const position = positionBuffer + glyphIndex;
- if(baseline < position->y + glyphInfo->yBearing)
+ Vector2 position = *(positionBuffer + glyphIndex);
+
+ if(addHyphen)
+ {
+ GlyphInfo tempInfo = *(glyphsBuffer + glyphIndex);
+ position.x = position.x + tempInfo.advance - tempInfo.xBearing + glyphInfo->xBearing;
+ position.y = -glyphInfo->yBearing;
+ }
+
+ if(baseline < position.y + glyphInfo->yBearing)
{
- baseline = position->y + glyphInfo->yBearing;
+ baseline = position.y + glyphInfo->yBearing;
}
// Calculate the positions of leftmost and rightmost glyphs in the current line
- if(position->x < lineExtentLeft)
+ if(position.x < lineExtentLeft)
{
- lineExtentLeft = position->x;
+ lineExtentLeft = position.x;
}
- if(position->x + glyphInfo->width > lineExtentRight)
+ if(position.x + glyphInfo->width > lineExtentRight)
{
- lineExtentRight = position->x + glyphInfo->width;
+ lineExtentRight = position.x + glyphInfo->width;
}
// Retrieves the glyph's color.
// Set the buffer of the glyph's bitmap into the final bitmap's buffer
TypesetGlyph(glyphData,
- position,
+ &position,
&color,
style,
pixelFormat);
delete[] glyphData.glyphBitmap.buffer;
glyphData.glyphBitmap.buffer = NULL;
}
+
+ while((hyphenIndex < hyphensCount) && (glyphIndex > hyphenIndices[hyphenIndex]))
+ {
+ hyphenIndex++;
+ }
+
+ addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && ((glyphIndex + 1) == hyphenIndices[hyphenIndex]));
+ if(addHyphen)
+ {
+ glyphIndex--;
+ }
}
// Draw the underline from the leftmost glyph to the rightmost glyph
return mModel->IsMarkupProcessorEnabled();
}
+const GlyphInfo* ViewModel::GetHyphens() const
+{
+ return mModel->GetHyphens();
+}
+
+const Length* ViewModel::GetHyphenIndices() const
+{
+ return mModel->GetHyphenIndices();
+}
+
+Length ViewModel::GetHyphensCount() const
+{
+ return mModel->GetHyphensCount();
+}
+
void ViewModel::ElideGlyphs()
{
mIsTextElided = false;
bool IsMarkupProcessorEnabled() const override;
/**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const GlyphInfo* GetHyphens() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const Length* GetHyphenIndices() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ Length GetHyphensCount() const override;
+
+ /**
* @brief Does the text elide.
*
* It stores a copy of the visible glyphs and removes as many glyphs as needed
#include <dali-toolkit/internal/text/character-set-conversion.h>
#include <dali-toolkit/internal/text/color-segmentation.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
#include <dali-toolkit/internal/text/multi-language-support.h>
#include <dali-toolkit/internal/text/segmentation.h>
#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-run-container.h>
#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+
using namespace Dali;
namespace
requestedNumberOfCharacters,
lineBreakInfo);
+ if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+ {
+ CharacterIndex end = startIndex + requestedNumberOfCharacters;
+ LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ for(CharacterIndex index = startIndex; index < end; index++)
+ {
+ CharacterIndex wordEnd = index;
+ while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+ {
+ wordEnd++;
+ }
+
+ if((wordEnd + 1) == end) // add last char
+ {
+ wordEnd++;
+ }
+
+ Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+ for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+ {
+ if(hyphens[i])
+ {
+ *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+ }
+ }
+
+ index = wordEnd;
+ }
+ }
+
// Create the paragraph info.
mModel->mLogicalModel->CreateParagraphInfo(startIndex,
requestedNumberOfCharacters);
#include <limits>
// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
#include <dali-toolkit/internal/text/text-controller-event-handler.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
#include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
{
if(lineWrapMode != mImpl->mModel->mLineWrapMode)
{
- // Set the text wrap mode.
- mImpl->mModel->mLineWrapMode = lineWrapMode;
-
// Update Text layout for applying wrap mode
- mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
+ mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
ALIGN |
LAYOUT |
UPDATE_LAYOUT_SIZE |
REORDER);
+
+ if((mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ (mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
+ {
+ mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | GET_LINE_BREAKS);
+ }
+
+ // Set the text wrap mode.
+ mImpl->mModel->mLineWrapMode = lineWrapMode;
+
mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
* @return The markup-processor state.
*/
virtual bool IsMarkupProcessorEnabled() const = 0;
+
+ /**
+ * @brief Returns the hyphens glyph info.
+ *
+ * @return hyphens glyph info.
+ */
+ virtual const GlyphInfo* GetHyphens() const = 0;
+
+ /**
+ * @brief Returns the indices of the hyphen in the text.
+ *
+ * @return the hyphen indices.
+ */
+ virtual const Length* GetHyphenIndices() const = 0;
+
+ /**
+ * @brief Returns number of hyphens to add in text.
+ *
+ * @return number of hyphens.
+ */
+ virtual Length GetHyphensCount() const = 0;
};
} // namespace Text
return mVisualModel->IsMarkupProcessorEnabled();
}
+const GlyphInfo* Model::GetHyphens() const
+{
+ return mVisualModel->mHyphen.glyph.Begin();
+}
+
+const Length* Model::GetHyphenIndices() const
+{
+ return mVisualModel->mHyphen.index.Begin();
+}
+
+Length Model::GetHyphensCount() const
+{
+ return mVisualModel->mHyphen.glyph.Size();
+}
+
Model::Model()
: mLogicalModel(),
mVisualModel(),
*/
bool IsMarkupProcessorEnabled() const override;
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const GlyphInfo* GetHyphens() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ const Length* GetHyphenIndices() const override;
+
+ /**
+ * @copydoc ModelInterface::GetHyphens()
+ */
+ Length GetHyphensCount() const override;
+
private: // Private contructors & copy operator.
/**
* @brief Private constructor.
virtual bool IsUnderlineEnabled() const = 0;
/**
+ * @brief Returns the hyphens glyph info.
+ *
+ * @return hyphens glyph info.
+ */
+ virtual const GlyphInfo* GetHyphens() const = 0;
+
+ /**
+ * @brief Returns the indices of the hyphen in the text.
+ *
+ * @return the hyphen indices.
+ */
+ virtual const Length* GetHyphenIndices() const = 0;
+
+ /**
+ * @brief Returns number of hyphens to add in text.
+ *
+ * @return number of hyphens.
+ */
+ virtual Length GetHyphensCount() const = 0;
+ /**
* @brief Retrieves the underline height override
*
* @return Returns the override height for an underline, 0 indicates that adaptor will determine the height
return false;
}
+const GlyphInfo* View::GetHyphens() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->mHyphen.glyph.Begin();
+ }
+
+ return nullptr;
+}
+
+const Length* View::GetHyphenIndices() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->mHyphen.index.Begin();
+ }
+
+ return nullptr;
+}
+
+Length View::GetHyphensCount() const
+{
+ if(mImpl->mVisualModel)
+ {
+ return mImpl->mVisualModel->mHyphen.glyph.Size();
+ }
+
+ return 0;
+}
float View::GetUnderlineHeight() const
{
if(mImpl->mVisualModel)
bool IsUnderlineEnabled() const override;
/**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+ */
+ const GlyphInfo* GetHyphens() const override;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+ */
+ const Length* GetHyphenIndices() const override;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+ */
+ Length GetHyphensCount() const override;
+
+ /**
* @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineHeight()
*/
float GetUnderlineHeight() const override;
{
namespace Text
{
+struct HyphenInfo
+{
+ Vector<GlyphInfo> glyph;
+ Vector<Vector2> position;
+ Vector<Length> index;
+};
+
class VisualModel;
typedef IntrusivePtr<VisualModel> VisualModelPtr;
bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set?
bool mBackgroundEnabled : 1; ///< Background enabled flag
bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
+ HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after.
};
} // namespace Text