// INTERNAL INCLUDES
#include <singleton-service-impl.h>
-#include <dali/public-api/text-abstraction/font-client.h>
-#include <dali/public-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
#include <dali/integration-api/debug.h>
// EXTERNAL INCLUDES
#include <harfbuzz/hb-ft.h>
#include <ft2build.h>
+#include <iostream>
namespace Dali
{
namespace Internal
{
-const unsigned int HIGH_QUALITY_PIXEL_SIZE = 200u; // Pixel size sent to FreeType2 FT_Set_Char_Size() for high quality glyphs.
const char* DEFAULT_LANGUAGE = "en";
const unsigned int DEFAULT_LANGUAGE_LENGTH = 2u;
-const float TO_PIXELS = 64.f;
+const float FROM_266 = 1.0f / 64.0f;
const hb_script_t SCRIPT_TO_HARFBUZZ[] =
{
+ HB_SCRIPT_COMMON,
+
+ HB_SCRIPT_COMMON, // ASCII_DIGITS
+ HB_SCRIPT_COMMON, // ASCII_PS
+
+ HB_SCRIPT_COMMON, // C1_CONTROLS
+ HB_SCRIPT_COMMON, // C1_PS
+ HB_SCRIPT_COMMON, // C1_MATH
+ HB_SCRIPT_COMMON, // SML_P
+ HB_SCRIPT_COMMON, // PHONETIC_U
+ HB_SCRIPT_COMMON, // PHONETIC_SS
+ HB_SCRIPT_COMMON, // NUMERIC_SS
+ HB_SCRIPT_COMMON, // LETTER_LIKE
+ HB_SCRIPT_COMMON, // NUMBER_FORMS
+ HB_SCRIPT_COMMON, // FRACTIONS_NF
+ HB_SCRIPT_COMMON, // NON_LATIN_LED
+ HB_SCRIPT_COMMON, // HWFW_S
+
+ HB_SCRIPT_CYRILLIC,
+ HB_SCRIPT_GREEK,
HB_SCRIPT_LATIN,
+
HB_SCRIPT_ARABIC,
- HB_SCRIPT_DEVANAGARI,
+ HB_SCRIPT_HEBREW,
+
+ HB_SCRIPT_ARMENIAN,
+ HB_SCRIPT_GEORGIAN,
+
+ HB_SCRIPT_HAN,
+ HB_SCRIPT_HANGUL,
+ HB_SCRIPT_HIRAGANA,
+ HB_SCRIPT_KATAKANA,
+ HB_SCRIPT_BOPOMOFO,
+
HB_SCRIPT_BENGALI,
- HB_SCRIPT_GURMUKHI,
+ HB_SCRIPT_MYANMAR,
+ HB_SCRIPT_DEVANAGARI,
HB_SCRIPT_GUJARATI,
- HB_SCRIPT_ORIYA,
- HB_SCRIPT_TAMIL,
- HB_SCRIPT_TELUGU,
+ HB_SCRIPT_GURMUKHI,
HB_SCRIPT_KANNADA,
HB_SCRIPT_MALAYALAM,
+ HB_SCRIPT_ORIYA,
HB_SCRIPT_SINHALA,
- HB_SCRIPT_HAN,
- HB_SCRIPT_HANGUL,
- HB_SCRIPT_KHMER,
+ HB_SCRIPT_TAMIL,
+ HB_SCRIPT_TELUGU,
+
HB_SCRIPT_LAO,
HB_SCRIPT_THAI,
- HB_SCRIPT_MYANMAR,
+ HB_SCRIPT_KHMER,
+ HB_SCRIPT_JAVANESE,
+ HB_SCRIPT_SUNDANESE,
+
+ HB_SCRIPT_ETHIOPIC,
+ HB_SCRIPT_OL_CHIKI,
+ HB_SCRIPT_TAGALOG,
+ HB_SCRIPT_MEETEI_MAYEK,
+
+ HB_SCRIPT_UNKNOWN, // EMOJI
+ HB_SCRIPT_UNKNOWN, // SYMBOLS1
+ HB_SCRIPT_UNKNOWN, // SYMBOLS2
+ HB_SCRIPT_UNKNOWN, // SYMBOLS3
+ HB_SCRIPT_UNKNOWN, // SYMBOLS4
+ HB_SCRIPT_UNKNOWN, // SYMBOLS5
HB_SCRIPT_UNKNOWN
};
mIndices.Clear();
mAdvance.Clear();
mCharacterMap.Clear();
+ mOffset.Clear();
mFontId = fontId;
+ // Reserve some space to avoid reallocations.
+ const Length numberOfGlyphs = static_cast<Length>( 1.3f * static_cast<float>( numberOfCharacters ) );
+ mIndices.Reserve( numberOfGlyphs );
+ mAdvance.Reserve( numberOfGlyphs );
+ mCharacterMap.Reserve( numberOfGlyphs );
+ mOffset.Reserve( 2u * numberOfGlyphs );
+
TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
// Get the font's path file name from the font Id.
return 0u;
}
- FT_Set_Pixel_Sizes( face, HIGH_QUALITY_PIXEL_SIZE, HIGH_QUALITY_PIXEL_SIZE );
+ unsigned int horizontalDpi = 0u;
+ unsigned int verticalDpi = 0u;
+ fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+ FT_Set_Char_Size( face,
+ 0u,
+ fontClient.GetPointSize( fontId ),
+ horizontalDpi,
+ verticalDpi );
/* Get our harfbuzz font struct */
hb_font_t* harfBuzzFont;
hb_buffer_set_script( harfBuzzBuffer,
SCRIPT_TO_HARFBUZZ[ script ] ); /* see hb-unicode.h */
- hb_buffer_set_language( harfBuzzBuffer,
- hb_language_from_string( DEFAULT_LANGUAGE,
- DEFAULT_LANGUAGE_LENGTH ) );
+
+ char* currentLocale = setlocale(LC_MESSAGES,NULL);
+
+ std::istringstream stringStream( currentLocale );
+ std::string localeString;
+ std::getline(stringStream, localeString, '_');
+ hb_buffer_set_language( harfBuzzBuffer, hb_language_from_string( localeString.c_str(), localeString.size() ) );
/* Layout the text */
hb_buffer_add_utf32( harfBuzzBuffer, text, numberOfCharacters, 0u, numberOfCharacters );
unsigned int glyphCount;
hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( harfBuzzBuffer, &glyphCount );
hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions( harfBuzzBuffer, &glyphCount );
-
- const Length lastGlyphIndex = glyphCount - 1u;
- for( Length i = 0u; i < glyphCount; ++i )
+ const GlyphIndex lastGlyphIndex = glyphCount - 1u;
+ for( GlyphIndex i = 0u; i < glyphCount; )
{
- // If the direction is right to left, Harfbuzz retrieves the glyphs in the visual order.
- // The glyphs are needed in the logical order to layout the text in lines.
- const Length index = rtlDirection ? ( lastGlyphIndex - i ) : i;
-
- mIndices.PushBack( glyphInfo[index].codepoint );
- mAdvance.PushBack( glyphPositions[index].x_advance / TO_PIXELS );
- mCharacterMap.PushBack( glyphInfo[index].cluster );
+ if( rtlDirection )
+ {
+ // If the direction is right to left, Harfbuzz retrieves the glyphs in the visual order.
+ // The glyphs are needed in the logical order to layout the text in lines.
+ // Do not change the order of the glyphs if they belong to the same cluster.
+ GlyphIndex rtlIndex = lastGlyphIndex - i;
+
+ unsigned int cluster = glyphInfo[rtlIndex].cluster;
+ unsigned int previousCluster = cluster;
+ Length numberOfGlyphsInCluster = 0u;
+
+ while( ( cluster == previousCluster ) )
+ {
+ ++numberOfGlyphsInCluster;
+ previousCluster = cluster;
+
+ if( rtlIndex > 0u )
+ {
+ --rtlIndex;
+
+ cluster = glyphInfo[rtlIndex].cluster;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ rtlIndex = lastGlyphIndex - ( i + ( numberOfGlyphsInCluster - 1u ) );
+
+ for( GlyphIndex j = 0u; j < numberOfGlyphsInCluster; ++j )
+ {
+ const GlyphIndex index = rtlIndex + j;
+
+ mIndices.PushBack( glyphInfo[index].codepoint );
+ mAdvance.PushBack( floor( glyphPositions[index].x_advance * FROM_266 ) );
+ mCharacterMap.PushBack( glyphInfo[index].cluster );
+ mOffset.PushBack( floor( glyphPositions[index].x_offset * FROM_266 ) );
+ mOffset.PushBack( floor( glyphPositions[index].y_offset * FROM_266 ) );
+ }
+
+ i += numberOfGlyphsInCluster;
+ }
+ else
+ {
+ mIndices.PushBack( glyphInfo[i].codepoint );
+ mAdvance.PushBack( floor( glyphPositions[i].x_advance * FROM_266 ) );
+ mCharacterMap.PushBack( glyphInfo[i].cluster );
+ mOffset.PushBack( floor( glyphPositions[i].x_offset * FROM_266 ) );
+ mOffset.PushBack( floor( glyphPositions[i].y_offset * FROM_266 ) );
+
+ ++i;
+ }
}
/* Cleanup */
{
Vector<CharacterIndex>::ConstIterator indicesIt = mIndices.Begin();
Vector<float>::ConstIterator advanceIt = mAdvance.Begin();
+ Vector<float>::ConstIterator offsetIt = mOffset.Begin();
Vector<CharacterIndex>::ConstIterator characterMapIt = mCharacterMap.Begin();
- for( Length index = 0u, size = mIndices.Count(); index < size; ++index )
+ for( GlyphIndex index = 0u, size = mIndices.Count(); index < size; ++index )
{
GlyphInfo& glyph = *( glyphInfo + index );
CharacterIndex& glyphToCharacter = *( glyphToCharacterMap + index );
glyph.index = *( indicesIt + index );
glyph.advance = *( advanceIt + index );
+ const GlyphIndex offsetIndex = 2u * index;
+ glyph.xBearing = *( offsetIt + offsetIndex );
+ glyph.yBearing = *( offsetIt + offsetIndex + 1u );
+
glyphToCharacter = *( characterMapIt + index );
}
}
Vector<CharacterIndex> mIndices;
Vector<float> mAdvance;
+ Vector<float> mOffset;
Vector<CharacterIndex> mCharacterMap;
FontId mFontId;
};