Skip to content

feat(text): Shape Arabic, right-to-left and emoji text with Uniscribe - #628

Closed
MAWKLY-VK wants to merge 5 commits into
GeneralsOnlineDevelopmentTeam:mainfrom
MAWKLY-VK:go/shaped-complex-text
Closed

MAWKLY-VK wants to merge 5 commits into
GeneralsOnlineDevelopmentTeam:mainfrom
MAWKLY-VK:go/shaped-complex-text

Conversation

@MAWKLY-VK

Copy link
Copy Markdown

Problem

Arabic text is disconnected and runs from left to right, emoji show up as boxes, and sentences that mix Arabic and English appear scrambled.

Result

It is now possible to write Arabic correctly and to write emoji.

Screenshots

Before:

sshot_20260930_180556_439

After:

image

Testing

I tested typing in a TheSuperHackers build on LAN. The parts specific to Generals Online (lobby chat coming from the server) were not tested in a Generals Online build, and we rely on the build check.

AI assistance

AI was used to help solve the problem more accurately and faster.

Brings the runtime loader of usp10.dll from TheSuperHackers/GeneralsGameCode in
its current form in Dependencies/Usp10 (TheSuperHackers#3241, TheSuperHackers#3342), so that the Uniscribe
functions can be called as if usp10.dll was linked statically. It includes
ScriptString_pLogAttr, ScriptStringGetLogicalWidths and ScriptStringCPtoX for
wrapping shaped text and placing a caret in it.

The only difference to the upstream file is the include of stringex.h, which
is still in WWLib here.
The glyph cache of FontCharsClass draws every UTF-16 unit on its own from left
to right. Arabic and Persian letters therefore appear unjoined and in reverse
order, emoji and other characters outside of the Basic Multilingual Plane
appear as two boxes, and characters that the font does not have appear as
boxes as well.

Text that needs it is now laid out with the ScriptString functions of
Uniscribe and drawn as a whole into the sentence textures:

* Letters are shaped and each paragraph is ordered with the Unicode
  Bidirectional Algorithm. A paragraph reads in the direction of most of its
  strong characters, so that a mostly Arabic message that starts with an
  English word keeps the Arabic reading order.
* Missing glyphs, including emoji, come from fallback fonts of the system.
  Glyphs are drawn in the text color like all other text.
* Word wrapping breaks paragraphs at soft break opportunities before each
  line is shaped, so wrapped chat messages stay readable. Lines of
  right-to-left paragraphs are aligned to the right.
* Directional isolates are replaced by embeddings, because Uniscribe does
  not support them.

Latin-1 text, and other text that the font can draw, such as Cyrillic, keeps
using the glyph cache and looks the same as before.

Text entries place the caret after the last character of right-to-left text
and start right-to-left text at the right edge of the entry.
…ailable

Allocate_New_Surface leaves no surface behind when the D3D surface cannot be
created. Build_Shaped_Sentence now stops in that case, and when a surface
cannot be locked, so that the sentence falls back to the glyph cache instead
of writing through a null pointer.
…at lines

A chat line such as "[name] message" is one paragraph. When the name is English
and the message mixes Arabic and English, the parts of the Arabic message end
up in left-to-right order around the English words and read in the wrong order.

Player names and messages that contain right-to-left characters are now
wrapped in Unicode first strong isolates, so that each keeps its own reading
order within the line. Chat lines without right-to-left characters are not
changed.
…d lobby chat

The services send room and lobby chat as one line, such as "[name] message" or
"[tag] [name] message". When the name is English and the message mixes Arabic
and English, the parts of the Arabic message end up in left-to-right order
around the English words.

IsolateBidiChatLine applies IsolateBidiText to the names in the leading
brackets and to the message after them, so that each keeps its own reading
order. Lines without right-to-left characters are not changed.
@MAWKLY-VK MAWKLY-VK closed this Oct 1, 2026
@MAWKLY-VK
MAWKLY-VK deleted the go/shaped-complex-text branch October 1, 2026 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant