mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-16 05:55:06 +03:00
More fixes for RTL.
This commit is contained in:
@@ -15,6 +15,7 @@ struct TextLayout {
|
||||
std::vector<ShapedGlyph> shapedGlyphs;
|
||||
std::vector<Float> linesWidth;
|
||||
Sizef size;
|
||||
bool isRTL{ false };
|
||||
};
|
||||
|
||||
class EE_API TextLayouter {
|
||||
|
||||
@@ -1034,16 +1034,20 @@ Vector2f Text::findCharacterPos( std::size_t index, Font* font, const Uint32& fo
|
||||
csg = &sg;
|
||||
}
|
||||
|
||||
if ( sg.stringIndex == index )
|
||||
if ( sg.stringIndex == index ) {
|
||||
if ( layout.isRTL )
|
||||
return ( sg.position + sg.advance ).trunc();
|
||||
return sg.position.trunc();
|
||||
}
|
||||
}
|
||||
|
||||
if ( !layout.shapedGlyphs.empty() && index >= maxStringIndex + 1 && msg ) {
|
||||
if ( !layout.shapedGlyphs.empty() && !layout.isRTL && index >= maxStringIndex + 1 && msg ) {
|
||||
Glyph metrics = msg->font->getGlyphByIndex( msg->glyphIndex, fontSize, bold, italic,
|
||||
outlineThickness );
|
||||
if ( string[msg->stringIndex] == '\t' ) {
|
||||
Float advance = Text::tabAdvance(
|
||||
hspace, tabWidth, tabOffset ? *tabOffset : std::optional<Float>{} );
|
||||
Float advance = Text::tabAdvance( hspace, tabWidth,
|
||||
tabOffset ? msg->position.x + *tabOffset
|
||||
: std::optional<Float>{} );
|
||||
return ( msg->position + Vector2f{ advance, 0 } ).trunc();
|
||||
}
|
||||
return ( msg->position + Vector2f{ metrics.advance, 0 } ).trunc();
|
||||
@@ -1143,7 +1147,8 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
|
||||
Float charRight;
|
||||
|
||||
bool isLastOnLine =
|
||||
( i + 1 == sgs || layout.shapedGlyphs[i + 1].position.y != sg.position.y );
|
||||
i + 1 == sgs ||
|
||||
( !layout.isRTL && layout.shapedGlyphs[i + 1].position.y != sg.position.y );
|
||||
|
||||
if ( !isLastOnLine ) {
|
||||
// The cell extends to the beginning of the next glyph
|
||||
@@ -1162,13 +1167,24 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
|
||||
// --- Direct Hit Test ---
|
||||
// Check if the point is within the vertical bounds of the current line
|
||||
if ( fpos.y >= charTop && fpos.y <= charBottom ) {
|
||||
auto findNextInsertionIndex = [&]() -> Int32 {
|
||||
auto findNextInsertionIndex = []( size_t i, size_t sgs, const ShapedGlyph& sg,
|
||||
const TextLayout& layout, auto& tSize ) -> Int32 {
|
||||
// Return insertion point after this glyph. Find the next distinct stringIndex.
|
||||
for ( size_t j = i + 1; j < sgs; ++j ) {
|
||||
if ( layout.shapedGlyphs[j].stringIndex > sg.stringIndex )
|
||||
return layout.shapedGlyphs[j].stringIndex;
|
||||
if ( layout.isRTL ) {
|
||||
if ( i > 0 ) {
|
||||
for ( Int64 j = (Int64)i - 1; j >= 0; j-- ) {
|
||||
if ( layout.shapedGlyphs[j].stringIndex > sg.stringIndex )
|
||||
return layout.shapedGlyphs[j].stringIndex;
|
||||
}
|
||||
}
|
||||
return 0; // Reached the end
|
||||
} else {
|
||||
for ( size_t j = i + 1; j < sgs; ++j ) {
|
||||
if ( layout.shapedGlyphs[j].stringIndex > sg.stringIndex )
|
||||
return layout.shapedGlyphs[j].stringIndex;
|
||||
}
|
||||
return tSize; // Reached the end
|
||||
}
|
||||
return tSize; // Reached the end
|
||||
};
|
||||
|
||||
// Case 1: Point is within the horizontal bounds of this glyph's cell
|
||||
@@ -1177,12 +1193,12 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
|
||||
if ( fpos.x < midPoint ) {
|
||||
return sg.stringIndex;
|
||||
} else {
|
||||
return findNextInsertionIndex();
|
||||
return findNextInsertionIndex( i, sgs, sg, layout, tSize );
|
||||
}
|
||||
}
|
||||
// Case 2: Point is to the right of the last glyph on the line
|
||||
else if ( isLastOnLine && fpos.x >= charRight ) {
|
||||
return findNextInsertionIndex();
|
||||
return findNextInsertionIndex( i, sgs, sg, layout, tSize );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@ static SBScriptLocator* getThreadLocalSbScriptLocator() {
|
||||
}
|
||||
|
||||
// Split string into segments with uniform text properties
|
||||
template <typename Callable> static void segmentString( String::View input, Callable cb ) {
|
||||
template <typename Callable>
|
||||
static void segmentString( TextLayout& result, String::View input, Callable cb ) {
|
||||
const SBCodepointSequence codepointSequence{
|
||||
SBStringEncodingUTF32, static_cast<const void*>( input.data() ), input.size() };
|
||||
auto* const scriptLocator = getThreadLocalSbScriptLocator();
|
||||
@@ -109,6 +110,9 @@ template <typename Callable> static void segmentString( String::View input, Call
|
||||
SBScriptLocatorReset( scriptLocator );
|
||||
}
|
||||
|
||||
if ( runCount > 0 && paragraphOffset == 0 )
|
||||
result.isRTL = ( runArray[0].level % 2 ) != 0;
|
||||
|
||||
SBLineRelease( line );
|
||||
SBParagraphRelease( paragraph );
|
||||
|
||||
@@ -119,12 +123,12 @@ template <typename Callable> static void segmentString( String::View input, Call
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
static void shapeAndRun( const String& string, FontTrueType* font, Uint32 characterSize,
|
||||
Uint32 style, Float outlineThickness, Callable cb ) {
|
||||
static void shapeAndRun( TextLayout& result, const String& string, FontTrueType* font,
|
||||
Uint32 characterSize, Uint32 style, Float outlineThickness, Callable cb ) {
|
||||
String::View input = string.view();
|
||||
hb_buffer_t* hbBuffer = getThreadLocalHbBuffer();
|
||||
|
||||
segmentString( input, [&]( const TextSegment& segment ) {
|
||||
segmentString( result, input, [&]( const TextSegment& segment ) {
|
||||
TextShapeRun run( input.substr( segment.offset, segment.length ), font, characterSize,
|
||||
style, outlineThickness, segment.direction == HB_DIRECTION_RTL );
|
||||
|
||||
@@ -225,6 +229,7 @@ TextLayout TextLayouter::layout( const StringType& string, Font* font, const Uin
|
||||
|
||||
bool bold = ( style & Text::Bold ) != 0;
|
||||
bool italic = ( style & Text::Italic ) != 0;
|
||||
Uint32 spaceGlyphIndex = 0;
|
||||
Float hspace = font->getGlyph( ' ', characterSize, bold, italic, outlineThickness ).advance;
|
||||
Float vspace = font->getLineSpacing( characterSize );
|
||||
Vector2f pen;
|
||||
@@ -235,7 +240,7 @@ TextLayout TextLayouter::layout( const StringType& string, Font* font, const Uin
|
||||
!Text::canSkipShaping( textDrawHints ) ) {
|
||||
FontTrueType* rFont = static_cast<FontTrueType*>( font );
|
||||
shapeAndRun(
|
||||
string, rFont, characterSize, style, outlineThickness,
|
||||
result, string, rFont, characterSize, style, outlineThickness,
|
||||
[&]( hb_glyph_info_t* glyphInfo, hb_glyph_position_t* glyphPos, Uint32 glyphCount,
|
||||
const hb_segment_properties_t& props, const TextSegment& segment,
|
||||
TextShapeRun& run ) {
|
||||
@@ -256,7 +261,11 @@ TextLayout TextLayouter::layout( const StringType& string, Font* font, const Uin
|
||||
: std::optional<Float>{} );
|
||||
ShapedGlyph sg;
|
||||
sg.font = currentRunFont;
|
||||
sg.glyphIndex = glyphInfo[i].codepoint;
|
||||
if ( spaceGlyphIndex == 0 && font->getType() == FontType::TTF ) {
|
||||
spaceGlyphIndex =
|
||||
static_cast<FontTrueType*>( font )->getGlyphIndex( ' ' );
|
||||
}
|
||||
sg.glyphIndex = spaceGlyphIndex;
|
||||
sg.stringIndex = segment.offset + run.pos() + cluster;
|
||||
sg.position = pen;
|
||||
sg.advance = { advance, 0 };
|
||||
@@ -280,12 +289,9 @@ TextLayout TextLayouter::layout( const StringType& string, Font* font, const Uin
|
||||
sg.font = currentRunFont;
|
||||
sg.glyphIndex = glyphInfo[i].codepoint;
|
||||
sg.stringIndex = segment.offset + run.pos() + glyphInfo[i].cluster;
|
||||
|
||||
float offsetX = glyphPos[i].x_offset / 64.f;
|
||||
float offsetY = glyphPos[i].y_offset / 64.f;
|
||||
sg.advance = { offsetX, offsetY };
|
||||
sg.position.x = pen.x + offsetX;
|
||||
sg.position.y = pen.y - offsetY;
|
||||
sg.advance = { currentGlyph.advance, 0 };
|
||||
sg.position.x = pen.x + ( glyphPos[i].x_offset / 64.f );
|
||||
sg.position.y = pen.y - ( glyphPos[i].y_offset / 64.f );
|
||||
result.shapedGlyphs.emplace_back( std::move( sg ) );
|
||||
|
||||
pen.x += currentGlyph.advance;
|
||||
@@ -317,19 +323,17 @@ TextLayout TextLayouter::layout( const StringType& string, Font* font, const Uin
|
||||
sg.font = currentRunFont;
|
||||
sg.glyphIndex = glyphInfo[i].codepoint;
|
||||
sg.stringIndex = segment.offset + run.pos() + glyphInfo[i].cluster;
|
||||
float offsetX = glyphPos[i].x_offset / 64.f;
|
||||
float offsetY = glyphPos[i].y_offset / 64.f;
|
||||
sg.advance = { offsetX, offsetY };
|
||||
sg.position.x = std::round( pen.x + offsetX );
|
||||
sg.position.y = std::round( pen.y - offsetY );
|
||||
sg.advance = { glyphPos[i].x_advance / 64.f, glyphPos[i].y_advance / 64.f };
|
||||
sg.position.x = std::round( pen.x + ( glyphPos[i].x_offset / 64.f ) );
|
||||
sg.position.y = std::round( pen.y - ( glyphPos[i].y_offset / 64.f ) );
|
||||
result.shapedGlyphs.emplace_back( std::move( sg ) );
|
||||
pen.x += Font::isEmojiCodePoint( ch )
|
||||
? currentRunFont
|
||||
->getGlyphByIndex( glyphInfo[i].codepoint, characterSize,
|
||||
bold, italic, outlineThickness )
|
||||
.advance
|
||||
: glyphPos[i].x_advance / 64.f;
|
||||
pen.y += glyphPos[i].y_advance / 64.f;
|
||||
: sg.advance.x;
|
||||
pen.y += sg.advance.y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user