bool markupProcessorEnabled,
LineWrap::Mode wrapMode,
bool ellipsisEnabled,
- DevelText::EllipsisPosition::Type ellipsisPosition)
+ DevelText::EllipsisPosition::Type ellipsisPosition,
+ float lineSpacing)
{
textModel = Model::New(); ///< Pointer to the text's model.
LogicalModelPtr logicalModel = textModel->mLogicalModel;
Layout::Engine layoutEngine;
layoutEngine.SetMetrics( metrics );
layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
+ layoutEngine.SetDefaultLineSpacing(lineSpacing);
// Set the layout parameters.
textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
* @param[in] wrapMode Line wrap mode.
* @param[in] ellipsisEnabled Whether the ellipsis layout option is enabled.
* @param[in] ellipsisPosition Where is the location the text elide.
+ * @param[in] lineSpacing The height of the line in points.
*/
void CreateTextModel( const std::string& text,
const Size& textArea,
bool markupProcessorEnabled,
LineWrap::Mode wrapMode,
bool ellipsisEnabled,
- DevelText::EllipsisPosition::Type ellipsisPosition);
+ DevelText::EllipsisPosition::Type ellipsisPosition,
+ float lineSpacing);
/**
* @brief Configures the text @p controller similarly to the one configured by the text-label.
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
data.markupProcessorEnabled,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
*/
#include <iostream>
-
#include <stdlib.h>
+#include <unistd.h>
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
namespace
{
+ const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+ const unsigned int DEFAULT_FONT_SIZE = 1152u;
struct GetClosestLineData
{
CharacterIndex* noTextHitIndex; ///< The expected character index when there is no hit.
};
+struct PrimaryCursorHeightData
+{
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int numberOfTests; ///< The number of tests.
+ CharacterIndex* logicalIndex; ///< The logical cursor index for each test.
+ float* heights; ///< The expected primary cursor height for each test.
+};
+
bool GetClosestLineTest( const GetClosestLineData& data )
{
std::cout << " testing : " << data.description << std::endl;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
parameters.logical = data.logicalIndex[index];
GetCursorPosition( parameters,
+ 0.f,// Since this test case is not testing the primary cursor height, the default font line height can be set to 0.f.
cursorInfo );
if( floor(cursorInfo.primaryPosition.x) != data.visualX[index] )
if( floor(cursorInfo.primaryPosition.y) != data.visualY[index] )
{
std::cout << " test " << index << " failed. Different 'y' cursor position : " << cursorInfo.primaryPosition.y << ", expected : " << data.visualY[index] << std::endl;
- return false;
+ return false;
}
}
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
return true;
}
+bool PrimaryCursorHeightTest( const PrimaryCursorHeightData& data )
+{
+ std::cout << " testing : " << data.description << std::endl;
+
+ // 1) Create the model.
+ ModelPtr textModel;
+ MetricsPtr metrics;
+ Size textArea(400.f, 600.f);
+ Size layoutSize;
+
+ Vector<FontDescriptionRun> fontDescriptionRuns;
+
+ 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 = true;
+ fontDescriptionRun1.size = 768u;//Font size = 12.0f (768/64 = 12)
+
+ fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+
+ LayoutOptions options;
+ CreateTextModel( data.text,
+ textArea,
+ fontDescriptionRuns,
+ options,
+ layoutSize,
+ textModel,
+ metrics,
+ false,
+ LineWrap::WORD,
+ false,
+ Toolkit::DevelText::EllipsisPosition::END,
+ 50.f );
+
+ LogicalModelPtr logicalModel = textModel->mLogicalModel;
+ VisualModelPtr visualModel = textModel->mVisualModel;
+
+ GetCursorPositionParameters parameters;
+ parameters.visualModel = visualModel;
+ parameters.logicalModel = logicalModel;
+ parameters.metrics = metrics;
+ parameters.isMultiline = true;
+
+ for( unsigned int index = 0; index < data.numberOfTests; ++index )
+ {
+ CursorInfo cursorInfo;
+ parameters.logical = data.logicalIndex[index];
+
+ // Load some fonts.
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ fontClient.SetDpi( 93u, 93u );
+
+ char* pathNamePtr = get_current_dir_name();
+ const std::string pathName( pathNamePtr );
+ free( pathNamePtr );
+
+ FontId fontID = fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSans.ttf" );
+
+ Text::FontMetrics fontMetrics;
+ MetricsPtr mMetrics = Metrics::New(fontClient);
+ mMetrics->GetFontMetrics(fontID, fontMetrics);
+ float defaultFontLineHeight = (fontMetrics.ascender - fontMetrics.descender);
+
+ GetCursorPosition( parameters,
+ defaultFontLineHeight,
+ cursorInfo );
+
+ if( floor(cursorInfo.primaryCursorHeight) != data.heights[index] )
+ {
+ std::cout << " test " << index << " failed. Different primaryCursorHeight : " << cursorInfo.primaryCursorHeight << ", expected : " << data.heights[index] << std::endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace
//////////////////////////////////////////////////////////
//
// UtcDaliGetClosestLine
// UtcDaliGetClosestCursorIndex
+// UtcDaliGetCursorPosition
+// UtcDaliFindSelectionIndices
+// UtcDaliPrimaryCursorHeight
//
//////////////////////////////////////////////////////////
tet_result(TET_PASS);
END_TEST;
}
+
+int UtcDaliPrimaryCursorHeight(void)
+{
+ tet_infoline(" UtcDaliPrimaryCursorHeight");
+
+ float heights[] = { 19.f };
+ CharacterIndex logicalIndex[] = { 1u };
+
+ struct PrimaryCursorHeightData data[] =
+ {
+ {
+ "Testing primary cursor height when line spacing is used.",
+ "Hello World",
+ 1u,
+ logicalIndex,
+ heights,
+ }
+ };
+ const unsigned int numberOfTests = 1u;
+
+ for( unsigned int index = 0; index < numberOfTests; ++index )
+ {
+ ToolkitTestApplication application;
+ if( !PrimaryCursorHeightTest( data[index] ) )
+ {
+ tet_result(TET_FAIL);
+ }
+ }
+
+ tet_result(TET_PASS);
+ END_TEST;
+}
false,
data.wrapMode,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
Vector<LineRun>& lines = textModel->mVisualModel->mLines;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
data.markupProcessorEnabled,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
false,
LineWrap::WORD,
false,
- Toolkit::DevelText::EllipsisPosition::END );
+ Toolkit::DevelText::EllipsisPosition::END,
+ 0.f );
LogicalModelPtr logicalModel = textModel->mLogicalModel;
VisualModelPtr visualModel = textModel->mVisualModel;
END_TEST;
}
+int utcDaliTextEditorSelectionWithSecondaryCursor(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" utcDaliTextEditorSelectionWithSecondaryCursor");
+
+ // Checks if the actor is created.
+
+ TextEditor editor = TextEditor::New();
+ DALI_TEST_CHECK( editor );
+
+ application.GetScene().Add( editor );
+
+ editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true );
+ editor.SetProperty( TextEditor::Property::TEXT, "اللغة العربية\nمرحبا بالجميع\nالسلام عليكم <span font-size='12' font-family='DejaVu Sans' >Hello world</span>" );
+ editor.SetProperty( TextEditor::Property::POINT_SIZE, 12.f );
+ editor.SetProperty( Actor::Property::SIZE, Vector2( 100.f, 50.f ) );
+ editor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+ editor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+ editor.SetProperty( DevelTextEditor::Property::MIN_LINE_SIZE, 50.f );
+ editor.SetProperty( DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, false );
+
+ // Avoid a crash when core load gl resources.
+ application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ // Tap on the text editor
+ TestGenerateTap( application, 3.0f, 25.0f );
+
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
+ //Select the last Arabic word (RTL) & some the space before the English (LTR) letters.
+ DevelTextEditor::SelectText( editor, 35, 41 );// This will activate the alternative cursor position and thus 'cursorInfo.isSecondaryCursor' will be true.
+
+ application.SendNotification();
+ application.Render();
+
+ std::string selectedText = editor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT ).Get<std::string>();
+ DALI_TEST_EQUALS( "عليكم ", selectedText, TEST_LOCATION );
+
+ END_TEST;
+}
+
int utcDaliTextEditorSelectionChangedSignal(void)
{
ToolkitTestApplication application;
}
void GetCursorPosition(GetCursorPositionParameters& parameters,
+ float defaultFontLineHeight,
CursorInfo& cursorInfo)
{
const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
const LineIndex lineIndex = parameters.visualModel->GetLineOfCharacter(characterOfLine);
const LineRun& line = *(modelLines + lineIndex);
+ const GlyphIndex* const charactersToGlyphBuffer = parameters.visualModel->mCharactersToGlyph.Begin();
+ const Length* const glyphsPerCharacterBuffer = parameters.visualModel->mGlyphsPerCharacter.Begin();
+ const GlyphInfo* const glyphInfoBuffer = parameters.visualModel->mGlyphs.Begin();
+ CharacterIndex index;
+ GlyphMetrics glyphMetrics;
+ MetricsPtr& metrics = parameters.metrics;
+ GlyphIndex glyphIndex = 0u;
+ Length numberOfGlyphs = 0u;
+
if(isLastNewParagraph)
{
// The cursor is in a new line with no characters. Place the cursor in that line.
cursorInfo.lineHeight = GetLineHeight(newLine);
+ const Length totalNumberOfCharacters = parameters.logicalModel->mText.Count();
+ index = totalNumberOfCharacters - 1;
+
+ GetGlyphMetricsFromCharacterIndex(index, glyphInfoBuffer, charactersToGlyphBuffer, glyphsPerCharacterBuffer, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
+
// Set the primary cursor's height.
- cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
+ // The primary cursor height will take the font height of the last character and if there are no characters, it'll take the default font line height.
+ cursorInfo.primaryCursorHeight = (totalNumberOfCharacters > 0) ? (cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight) : defaultFontLineHeight;
// Set the primary cursor's position.
cursorInfo.primaryPosition.x = (LTR == line.direction) ? newLine.alignmentOffset : parameters.visualModel->mControlSize.width - newLine.alignmentOffset;
// Calculate the primary cursor.
- CharacterIndex index = characterIndex;
+ index = characterIndex;
if(cursorInfo.isSecondaryCursor)
{
// If there is a secondary position, the primary cursor may be in a different place than the logical index.
}
}
- const GlyphIndex* const charactersToGlyphBuffer = parameters.visualModel->mCharactersToGlyph.Begin();
- const Length* const glyphsPerCharacterBuffer = parameters.visualModel->mGlyphsPerCharacter.Begin();
const Length* const charactersPerGlyphBuffer = parameters.visualModel->mCharactersPerGlyph.Begin();
const CharacterIndex* const glyphsToCharactersBuffer = parameters.visualModel->mGlyphsToCharacters.Begin();
const Vector2* const glyphPositionsBuffer = parameters.visualModel->mGlyphPositions.Begin();
- const GlyphInfo* const glyphInfoBuffer = parameters.visualModel->mGlyphs.Begin();
- // Convert the cursor position into the glyph position.
- const GlyphIndex primaryGlyphIndex = *(charactersToGlyphBuffer + index);
- const Length primaryNumberOfGlyphs = *(glyphsPerCharacterBuffer + index);
+ GetGlyphMetricsFromCharacterIndex(index, glyphInfoBuffer, charactersToGlyphBuffer, glyphsPerCharacterBuffer, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
+ const GlyphIndex primaryGlyphIndex = glyphIndex;
const Length primaryNumberOfCharacters = *(charactersPerGlyphBuffer + primaryGlyphIndex);
- // Get the metrics for the group of glyphs.
- GlyphMetrics glyphMetrics;
- GetGlyphsMetrics(primaryGlyphIndex,
- primaryNumberOfGlyphs,
- glyphMetrics,
- glyphInfoBuffer,
- parameters.metrics);
-
// Whether to add the glyph's advance to the cursor position.
// i.e if the paragraph is left to right and the logical cursor is zero, the position is the position of the first glyph and the advance is not added,
// if the logical cursor is one, the position is the position of the first glyph and the advance is added.
index = (isRightToLeftParagraph == isCurrentRightToLeft) ? nextCharacterIndex : characterIndex;
}
- const GlyphIndex secondaryGlyphIndex = *(charactersToGlyphBuffer + index);
- const Length secondaryNumberOfGlyphs = *(glyphsPerCharacterBuffer + index);
-
- const Vector2& secondaryPosition = *(glyphPositionsBuffer + secondaryGlyphIndex);
-
- GetGlyphsMetrics(secondaryGlyphIndex,
- secondaryNumberOfGlyphs,
- glyphMetrics,
- glyphInfoBuffer,
- parameters.metrics);
+ GetGlyphMetricsFromCharacterIndex(index, glyphInfoBuffer, charactersToGlyphBuffer, glyphsPerCharacterBuffer, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
+ const GlyphIndex secondaryGlyphIndex = glyphIndex;
+ const Vector2& secondaryPosition = *(glyphPositionsBuffer + secondaryGlyphIndex);
// Set the secondary cursor's position.
#include <dali-toolkit/internal/text/logical-model-impl.h>
#include <dali-toolkit/internal/text/metrics.h>
#include <dali-toolkit/internal/text/visual-model-impl.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
namespace Dali
{
* if there is a valid alternative cursor, its position and height.
*
* @param[in] parameters Parameters used to calculate the cursor's position.
+ * @param[in] defaultFontLineHeight The default font line height.
* @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
*/
void GetCursorPosition(GetCursorPositionParameters& parameters,
+ float defaultFontLineHeight,
CursorInfo& cursorInfo);
/**
glyphMetrics.width += (firstGlyph.isItalicRequired && !isItalicFont) ? TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE * firstGlyph.height : 0.f;
}
+void GetGlyphMetricsFromCharacterIndex(CharacterIndex index, const GlyphInfo* const glyphInfoBuffer, const GlyphIndex* const charactersToGlyphBuffer, const Length* const glyphsPerCharacterBuffer, MetricsPtr& metrics, GlyphMetrics& glyphMetrics, GlyphIndex& glyphIndex, Length& numberOfGlyphs)
+{
+ //Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
+ glyphIndex = *(charactersToGlyphBuffer + index);
+ numberOfGlyphs = *(glyphsPerCharacterBuffer + index);
+
+ // Get the metrics for the group of glyphs.
+ GetGlyphsMetrics(glyphIndex,
+ numberOfGlyphs,
+ glyphMetrics,
+ glyphInfoBuffer,
+ metrics);
+}
+
} // namespace Text
} // namespace Toolkit
const GlyphInfo* const glyphsBuffer,
MetricsPtr& metrics);
+/**
+ * @brief Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
+ *
+ * @param[in] index The character index.
+ * @param[in] glyphInfoBuffer The glyphs buffer.
+ * @param[in] charactersToGlyphBuffer A vector containing the glyph index for each character.
+ * @param[in] glyphsPerCharacterBuffer A vector containing the number of glyphs in each character.
+ * @param[in] metrics Used to access metrics from FontClient.
+ * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
+ * @param[out] glyphIndex The glyph index obtained from the character index.
+ * @param[out] numberOfGlyphs The number of glyphs in the character of which the index was passed to the function.
+ *
+ */
+void GetGlyphMetricsFromCharacterIndex(CharacterIndex index,
+ const GlyphInfo* const glyphInfoBuffer,
+ const GlyphIndex* const charactersToGlyphBuffer,
+ const Length* const glyphsPerCharacterBuffer,
+ MetricsPtr& metrics,
+ GlyphMetrics& glyphMetrics,
+ GlyphIndex& glyphIndex,
+ Length& numberOfGlyphs);
+
} // namespace Text
} // namespace Toolkit
parameters.logical = logical;
parameters.isMultiline = isMultiLine;
+ float defaultFontLineHeight = GetDefaultFontLineHeight();
+
Text::GetCursorPosition(parameters,
+ defaultFontLineHeight,
cursorInfo);
// Adds Outline offset.