Skip to content

feat(text): Add Unicode paragraph direction detection - #3291

Open
OmarAglan wants to merge 1 commit into
TheSuperHackers:mainfrom
OmarAglan:feature/unicode-paragraph-direction
Open

OmarAglan wants to merge 1 commit into
TheSuperHackers:mainfrom
OmarAglan:feature/unicode-paragraph-direction

Conversation

@OmarAglan

@OmarAglan OmarAglan commented Sep 14, 2026

Copy link
Copy Markdown

Adds a helper for finding a paragraph's first strong text direction. It decodes UTF-16 surrogate pairs and skips directional-isolate contents, allowing supplementary RTL characters to participate in paragraph-direction detection.

BMP classification uses Windows. Supplementary classification uses generated Unicode 17.0.0 data, with a reproducible generator, source checksum, and Unicode license. The helper is consumed by the separate complex-text rasterization change; this PR does not activate UI shaping.

Validation

  • Clean VC6 Release builds of Generals and Zero Hour.
  • 24 local paragraph-direction cases passed, including supplementary scripts, neutral characters, malformed surrogate pairs, and isolates.
  • Unicode table regeneration check and git diff --check.

Implementation developed with AI assistance.

@OmarAglan
OmarAglan marked this pull request as ready for review September 14, 2026 10:04
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add Unicode-aware paragraph direction detection

✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Detects paragraph direction from first strong UTF-16 character while excluding isolate contents.
• Classifies BMP text through Windows and supplementary code points through Unicode 17 data.
• Adds reproducible table generation with checksum validation and Unicode licensing.
Diagram

graph TD
  U["Unicode 17 Data"] --> G["Table Generator"] --> T["Bidi Ranges"] --> H["Direction Helper"] --> P["Paragraph Level"]
  W["Windows API"] --> H
  X["UTF-16 Text"] --> H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use a Unicode bidi library
2. Generate classification for all Unicode planes
  • ➕ Produces consistent behavior across Windows versions
  • ➕ Uses one Unicode version for BMP and supplementary characters
  • ➖ Requires a larger generated table
  • ➖ Duplicates BMP classification already available through Windows

Recommendation: Keep the PR's hybrid approach: Windows classification minimizes BMP data and preserves legacy compatibility, while generated Unicode 17 ranges address unreliable supplementary classification. A full bidi library would be preferable only if later shaping work requires substantially more of UAX #9; automated tests should accompany that future integration.

Files changed (5) +444 / -0

Enhancement (2) +349 / -0
supplementarybidi.inlAdd generated supplementary bidi ranges +265/-0

Add generated supplementary bidi ranges

• Adds Unicode 17.0.0 ranges for supplementary right-to-left and neutral code points. Omitted ranges default to left-to-right and are suitable for binary-search lookup.

Core/Libraries/Source/WWVegas/WW3D2/supplementarybidi.inl

unicodebidi.hImplement first-strong paragraph direction detection +84/-0

Implement first-strong paragraph direction detection

• Adds UTF-16 paragraph scanning that ignores directional-isolate contents, safely handles malformed surrogates, and decodes valid supplementary code points. BMP characters use GetStringTypeW, while supplementary characters use the generated range table.

Core/Libraries/Source/WWVegas/WW3D2/unicodebidi.h

Documentation (1) +39 / -0
unicode-license.txtInclude the Unicode data license +39/-0

Include the Unicode data license

• Documents the license governing the Unicode data used to generate supplementary bidi classifications.

Core/Libraries/Source/WWVegas/WW3D2/unicode-license.txt

Other (2) +56 / -0
CMakeLists.txtRegister Unicode bidi sources in WW3D2 +2/-0

Register Unicode bidi sources in WW3D2

• Adds the paragraph-direction header and generated supplementary table to the WW3D2 source list.

Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt

generate_supplementary_bidi.pyGenerate and verify supplementary bidi data +54/-0

Generate and verify supplementary bidi data

• Adds a reproducible Unicode 17.0.0 table generator with source-version and SHA-256 validation. It applies explicit and @missing classes, emits compact non-LTR ranges, and supports an out-of-date check mode.

scripts/generate_supplementary_bidi.py

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@greptile-apps

greptile-apps Bot commented Sep 14, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a UTF-16 paragraph-direction helper to WW3D2, backed by generated Unicode 17 supplementary-plane bidi data.

  • Decodes valid surrogate pairs and treats malformed surrogate code units as neutral.
  • Excludes nested directional-isolate contents while searching for the first strong character.
  • Uses Windows classification for BMP characters and a binary-searched generated table for supplementary characters.
  • Adds a checksum-pinned Python generator, Unicode license, generated data, and CMake source registration.
  • The implementation is coherent, but repository formatting, comment-date, license-header, and automated-test requirements remain to be addressed.

Confidence Score: 4/5

The direction-detection logic appears sound, but the PR should not merge until the explicit repository requirements for source prologues, comment dates, and control-statement formatting are satisfied.

No concrete runtime or build failure was established, but three repository-rule violations require correction; committed automated coverage is also needed to protect the nuanced UTF-16 and isolate behavior.

Files Needing Attention: Core/Libraries/Source/WWVegas/WW3D2/unicodebidi.h, Core/Libraries/Source/WWVegas/WW3D2/supplementarybidi.inl, scripts/generate_supplementary_bidi.py

Important Files Changed

Filename Overview
Core/Libraries/Source/WWVegas/WW3D2/unicodebidi.h Adds the UTF-16 first-strong direction algorithm; behavior is coherent, but control-body formatting and automated coverage need attention.
Core/Libraries/Source/WWVegas/WW3D2/supplementarybidi.inl Adds sorted generated Unicode supplementary bidi ranges, with repository comment-date and license-prologue violations.
scripts/generate_supplementary_bidi.py Adds a checksum-pinned reproducible table generator but omits the required GPL source prologue and does not preserve its validation cases as tests.
Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt Registers the new header and generated include data with the shared WW3D2 interface source set.
Core/Libraries/Source/WWVegas/WW3D2/unicode-license.txt Adds the Unicode data license associated with the generated classification table.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[UTF-16 paragraph] --> B[Read next code unit]
  B --> C{Isolate control?}
  C -->|Initiator| D[Increase isolate depth]
  C -->|PDI| E[Decrease positive depth]
  C -->|No| F{Inside isolate?}
  D --> B
  E --> B
  F -->|Yes| B
  F -->|No| G{Valid surrogate pair?}
  G -->|Yes| H[Decode supplementary code point]
  H --> I[Binary-search Unicode bidi ranges]
  G -->|No, valid BMP| J[Call GetStringTypeW]
  G -->|Malformed surrogate| B
  I --> K{Strong direction?}
  J --> K
  K -->|RTL| L[Return level 1]
  K -->|LTR| M[Return level 0]
  K -->|Neutral| B
  B -->|End of text| M
Loading
Prompt To Fix All With AI
### Issue 1
scripts/generate_supplementary_bidi.py:1
**Missing GPL Prologues**

The new generator and generated `.inl` file begin without GPL license headers. This violates the repository requirement that newly created source files include GPL headers and must be corrected before merging. The same issue appears in `Core/Libraries/Source/WWVegas/WW3D2/supplementarybidi.inl`.

### Issue 2
Core/Libraries/Source/WWVegas/WW3D2/supplementarybidi.inl:3
**Outdated Comment Date**

This newly added generated-code comment says `Copyright 2025 Unicode, Inc.`, and the generator emits the same text. That violates the repository requirement that new comments not reference dates before the current year, 2026, and must be corrected before merging.

### Issue 3
Core/Libraries/Source/WWVegas/WW3D2/unicodebidi.h:60
**Inline Control Bodies**

Several new `if` bodies are placed on the same line as their conditions, including the isolate-depth decrement, neutral-content skip, direction assignments, and final return. This violates the repository requirement to place control-statement bodies on separate lines for precise debugger breakpoints and must be corrected before merging.

### Issue 4
Core/Libraries/Source/WWVegas/WW3D2/unicodebidi.h:50-79
**Direction Logic Untested**

The new direction detector has no committed automated tests despite adding separate behavior for nested and unterminated isolates, malformed surrogate pairs, supplementary RTL ranges, and Windows BMP classification. Without preserving the stated local cases in the repository, later changes to this traversal or its generated table can silently regress paragraph direction.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat(text): Add Unicode paragraph direct..." | Re-trigger Greptile

@stephanmeesters

Copy link
Copy Markdown

Why do we need the unicode license and copyright headers?


Direction direction = Neutral;
if (ch >= 0xD800 && ch <= 0xDBFF) {
if (index + 1 < length && text[index + 1] >= 0xDC00 && text[index + 1] <= 0xDFFF) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you understand everything that's going on here or is it left to reviewers to figure out?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, the goal here is specifically paragraph base direction detection according to the first strong character, rather than implementing the complete bidi algorithm, so the loop do this at the moment:

  • it skips the contents of directional isolates for the paragraph direction decision, and safely decodes valid UTF-16 surrogate pairs
  • it ignores malformed surrogate sequences rather than treating them as directional characters, and uses GetStringTypeW(CT_CTYPE2) for BMP characters

it then uses the generated Unicode bidi class ranges for supplementary code points because GetStringTypeW does not reliably classify those, and returns level 0 or 1 when the first strong L or R or AL character is found.

my reason is this generated table is intentionally limited to what this helper needs rather than trying to duplicate make the whole the complete Unicode bidi algorithm (more code more complix, and it will take a lot of time)

well, i suppose we can improve the loop or i can add more comments if needed.

@OmarAglan

Copy link
Copy Markdown
Author

Why do we need the unicode license and copyright headers?

hmm this is the supplementary bidi table and it is generated from Unicode's DerivedBidiClass.txt, i included the unicode license because we are distributing generated data derived from the unicode data files.

if you read the license of unicode v3 , you would see that it requires the copyright and permission notice to be included with any copies of the data software or it can be included in associated documentation also the short copyright and license header on the generated .inl is there to make the to be more clear and it points to the full license

i suppose, if it will do no harm in anyway, i can remove it if needed

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.

2 participants