Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit ab3016f

Browse files
author
Fraser J. Gordon
committed
Initial implementation of basic RTL support
Still buggy and cursor movement is completely wrong.
1 parent 4e70fa6 commit ab3016f

22 files changed

+533
-67
lines changed

engine/src/MCBlock.h

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ class MCBlock : public MCDLlist
6262
Blockatts *atts;
6363
findex_t m_index, m_size;
6464
uint2 width;
65+
uint2 origin;
6566
uint2 opened;
67+
uint2 tabpos; // Pixel offset to use when calculating tabstops
68+
uint8_t direction_level;
6669

6770
// MW-2012-02-14: [[ FontRefs ]] The concrete font to use for the block.
6871
// (only valid when the block is open).
@@ -253,6 +256,47 @@ class MCBlock : public MCDLlist
253256
}
254257

255258
bool imagechanged(MCImage *p_image, bool p_deleting);
259+
260+
////////// BIDIRECTIONAL SUPPORT
261+
262+
uint2 getorigin() const
263+
{
264+
return origin;
265+
}
266+
267+
void setorigin(uint2 o)
268+
{
269+
origin = o;
270+
}
271+
272+
uint2 GetDirectionLevel() const
273+
{
274+
return direction_level;
275+
}
276+
277+
void SetDirectionLevel(uint8_t l)
278+
{
279+
direction_level = l;
280+
}
281+
282+
bool is_rtl() const
283+
{
284+
// If odd, text is right-to-left, otherwise left-to-right
285+
return GetDirectionLevel() & 1;
286+
}
287+
288+
uint2 getwidth(MCDC *dc = NULL)
289+
{
290+
if (is_rtl())
291+
return getwidth(dc, origin - width);
292+
else
293+
return getwidth(dc, origin);
294+
}
295+
296+
void settabpos(uint2 offset)
297+
{
298+
tabpos = offset;
299+
}
256300

257301
////////////////////
258302

@@ -272,10 +316,10 @@ class MCBlock : public MCDLlist
272316
void MoveRange(findex_t t_index_offset, findex_t t_length_offset);
273317

274318
// Translates from a pixel position to a cursor index
275-
findex_t GetCursorIndex(int2 x, int2 cx, Boolean chunk, Boolean last);
319+
findex_t GetCursorIndex(int2 x, Boolean chunk, Boolean last);
276320

277321
// Returns the x coordinate of the cursor
278-
uint2 GetCursorX(int2 x, findex_t fi);
322+
uint2 GetCursorX(findex_t fi);
279323

280324
// Moves the index forwards by one codepoint, possibly changing block
281325
MCBlock *AdvanceIndex(findex_t &x_index);
@@ -295,7 +339,7 @@ class MCBlock : public MCDLlist
295339
{
296340
return flags & F_HAS_UNICODE;
297341
}
298-
342+
299343
//////////
300344

301345
void GetLinkText(MCExecContext& ctxt, MCStringRef& r_linktext);

engine/src/block.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ MCBlock::MCBlock(void)
4848
m_index = m_size = 0;
4949
width = 0;
5050
opened = 0;
51+
origin = 0;
52+
tabpos = 0;
53+
direction_level = 0;
5154

5255
// MW-2012-02-14: [[ FontRefs ]] The font for the block starts off nil.
5356
m_font = nil;
@@ -99,6 +102,9 @@ MCBlock::MCBlock(const MCBlock &bref) : MCDLlist(bref)
99102
m_size = bref.m_size;
100103
width = 0;
101104
opened = 0;
105+
origin = 0;
106+
tabpos = 0;
107+
direction_level = bref.direction_level;
102108

103109
// MW-2012-02-14: [[ FontRefs ]] The font for the block starts off nil.
104110
m_font = nil;
@@ -607,6 +613,10 @@ Boolean MCBlock::sameatts(MCBlock *bptr, bool p_persistent_only)
607613
(bptr -> atts -> shift != atts -> shift))
608614
return False;
609615

616+
// Ensure that the direction level matches
617+
if (direction_level != bptr -> direction_level)
618+
return False;
619+
610620
// Everything matches, so these two blocks must be the same.
611621
return True;
612622
}
@@ -974,7 +984,7 @@ void MCBlock::drawstring(MCDC *dc, int2 x, int2 cx, int2 y, findex_t start, find
974984

975985
t_cell_clip = MCU_intersect_rect(t_cell_clip, t_old_clip);
976986
dc -> setclip(t_cell_clip);
977-
dc -> drawtext_substring(x, y, parent->GetInternalStringRef(), t_range, m_font, image == True);
987+
dc -> drawtext_substring(x, y, parent->GetInternalStringRef(), t_range, m_font, image == True, is_rtl());
978988

979989
// Only draw the various boxes/lines if there is any content.
980990
if (t_next_index - t_index > 0)
@@ -1049,7 +1059,7 @@ void MCBlock::drawstring(MCDC *dc, int2 x, int2 cx, int2 y, findex_t start, find
10491059
twidth = MCFontMeasureTextSubstring(m_font, parent->GetInternalStringRef(), t_range);
10501060
twidth += gettabwidth(cx + twidth, eptr);
10511061

1052-
dc -> drawtext_substring(x, y, parent->GetInternalStringRef(), t_range, m_font, image == True);
1062+
dc -> drawtext_substring(x, y, parent->GetInternalStringRef(), t_range, m_font, image == True, is_rtl());
10531063

10541064
cx += twidth;
10551065
x += twidth;
@@ -1071,7 +1081,7 @@ void MCBlock::drawstring(MCDC *dc, int2 x, int2 cx, int2 y, findex_t start, find
10711081

10721082
MCRange t_range;
10731083
t_range = MCRangeMake(sptr, size);
1074-
dc -> drawtext_substring(x, y, parent->GetInternalStringRef(), t_range, m_font, image == True);
1084+
dc -> drawtext_substring(x, y, parent->GetInternalStringRef(), t_range, m_font, image == True, is_rtl());
10751085

10761086
// Apply strike/underline.
10771087
if ((style & FA_UNDERLINE) != 0)
@@ -1622,21 +1632,30 @@ void MCBlock::setbackcolor(const MCColor *newcolor)
16221632
}
16231633
}
16241634

1625-
uint2 MCBlock::GetCursorX(int2 x, findex_t fi)
1635+
uint2 MCBlock::GetCursorX(findex_t fi)
16261636
{
16271637
findex_t j = fi - m_index;
16281638
if (j > m_size)
16291639
j = m_size;
1630-
return getsubwidth(NULL, x, m_index, j);
1640+
1641+
// [[ BiDi Support ]]
1642+
// If the block is RTL, x decreases as fi increases
1643+
if (is_rtl())
1644+
return origin + width - getsubwidth(NULL, tabpos, m_index, j);
1645+
else
1646+
return origin + getsubwidth(NULL, tabpos, m_index, j);
16311647
}
16321648

1633-
findex_t MCBlock::GetCursorIndex(int2 x, int2 cx, Boolean chunk, Boolean last)
1649+
findex_t MCBlock::GetCursorIndex(int2 x, Boolean chunk, Boolean last)
16341650
{
1635-
// MW-2007-07-05: [[ Bug 5099 ]] If we have an image and are unicode, the char
1651+
// The x coordinate is relative to the line, not ourselves
1652+
x -= getorigin();
1653+
1654+
// MW-2007-07-05: [[ Bug 5099 ]] If we have an image and are unicode, the char
16361655
// we replace is two bytes long
16371656
if (flags & F_HAS_IMAGE && atts->image != NULL)
16381657
{
1639-
if (chunk || cx < atts->image->getrect().width >> 1)
1658+
if (chunk || x < atts->image->getrect().width >> 1)
16401659
return m_index;
16411660
else
16421661
return m_index + 1;
@@ -1656,19 +1675,21 @@ findex_t MCBlock::GetCursorIndex(int2 x, int2 cx, Boolean chunk, Boolean last)
16561675
t_last_width = 0;
16571676
while(i < m_index + m_size)
16581677
{
1659-
int32_t t_new_i;
1678+
// TODO: broken for RTL
1679+
1680+
int32_t t_new_i;
16601681
t_new_i = parent->IncrementIndex(i);
16611682

16621683
int32_t t_new_width;
1663-
t_new_width = GetCursorX(x, t_new_i);
1684+
t_new_width = GetCursorX(t_new_i) - origin;
16641685

16651686
int32_t t_pos;
16661687
if (chunk)
16671688
t_pos = t_new_width;
16681689
else
16691690
t_pos = (t_last_width + t_new_width) / 2;
16701691

1671-
if (cx < t_pos)
1692+
if (x < t_pos)
16721693
break;
16731694

16741695
t_last_width = t_new_width;

engine/src/context.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class MCContext
159159
virtual void drawlines(MCPoint *points, uint2 npoints, bool p_closed = false) = 0;
160160
virtual void drawsegments(MCSegment *segments, uint2 nsegs) = 0;
161161
virtual void drawtext(int2 x, int2 y, MCStringRef p_string, MCFontRef p_font, Boolean image) = 0;
162-
virtual void drawtext_substring(int2 x, int2 y, MCStringRef p_string, MCRange p_range, MCFontRef p_font, Boolean image) = 0;
162+
virtual void drawtext_substring(int2 x, int2 y, MCStringRef p_string, MCRange p_range, MCFontRef p_font, Boolean image, bool rtl = false) = 0;
163163
virtual void drawrect(const MCRectangle& rect, bool inside = false) = 0;
164164
virtual void fillrect(const MCRectangle& rect, bool inside = false) = 0;
165165
virtual void fillrects(MCRectangle *rects, uint2 nrects) = 0;

engine/src/field.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@ typedef bool (*MCFieldExportCallback)(void *context, MCFieldExportEventType even
166166
struct MCInterfaceFlaggedRanges;
167167
struct MCInterfaceFlaggedRange;
168168

169+
// The values assigned to these constants are significant: they represent the
170+
// starting values in the Unicode BiDi algorithm and should not be changed.
171+
enum MCFieldTextDirection
172+
{
173+
kMCFieldTextDirectionAuto = -1, // Detect based on contents
174+
kMCFieldTextDirectionLTR = 0, // Force left-to-right direction
175+
kMCFieldTextDirectionRTL = 1, // Force right-to-left direction
176+
};
177+
178+
// Significant characters for BiDi processing
179+
#define kMCBidiLRE 0x202A // Left-to-right embedding
180+
#define kMCBidiRLE 0x202B // Right-to-left embedding
181+
#define kMCBidiLRO 0x202D // Left-to-right override
182+
#define kMCBidiRLO 0x202E // Right-to-left override
183+
#define kMCBidiPDF 0x202C // Pop directional formatting
184+
#define kMCBidiLRI 0x2066 // Left-to-right isolate
185+
#define kMCBidiRLI 0x2067 // Right-to-left isolate
186+
#define kMCBidiFSI 0x2068 // First strong isolate
187+
#define kMCBidiPDI 0x2069 // Pop directional isolate
188+
#define kMCBidiLRM 0x200E // Left-to-right mark
189+
#define kMCBidiRLM 0x200F // Right-to-left mark
190+
#define kMCBidiALM 0x061C // Arabic letter mark
191+
169192
////////////////////////////////////////////////////////////////////////////////
170193

171194
class MCField : public MCControl
@@ -199,6 +222,7 @@ class MCField : public MCControl
199222
MCScrollbar *vscrollbar;
200223
MCScrollbar *hscrollbar;
201224
MCStringRef label;
225+
MCFieldTextDirection text_direction;
202226

203227
static int2 clickx;
204228
static int2 clicky;
@@ -611,6 +635,9 @@ class MCField : public MCControl
611635

612636
bool imagechanged(MCImage *p_image, bool p_deleting);
613637

638+
////////// BIDIRECTIONAL SUPPORT
639+
640+
MCFieldTextDirection getbasetextdirection() { return text_direction; }
614641

615642
////////// PROPERTY SUPPORT METHODS
616643

engine/src/font.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
3434
#include "graphics_util.h"
3535
#include "unicode.h"
3636

37+
#include "foundation-unicode.h"
38+
3739
////////////////////////////////////////////////////////////////////////////////
3840

3941
#define kMCFontBreakTextCharLimit 64
@@ -156,7 +158,7 @@ int32_t MCFontGetDescent(MCFontRef self)
156158
return self -> fontstruct -> descent;
157159
}
158160

159-
void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFontBreakTextCallback p_callback, void *p_callback_data)
161+
void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFontBreakTextCallback p_callback, void *p_callback_data, bool p_rtl)
160162
{
161163
// Scan forward in the string for possible break locations. Breaks are
162164
// assigned a quality value as some locations are better for breaking than
@@ -172,6 +174,8 @@ void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFo
172174
uint32_t t_stride;
173175
t_stride = kMCFontBreakTextCharLimit;
174176

177+
uindex_t t_end = p_range.offset + p_range.length;
178+
175179
uindex_t t_length = p_range.length;
176180
uindex_t t_offset = p_range.offset;
177181

@@ -191,11 +195,19 @@ void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFo
191195
codepoint_t t_char;
192196
uindex_t t_advance;
193197

194-
t_char = MCStringGetCharAtIndex(p_text, t_offset + t_index);
195-
if (0xD800 <= t_char && t_char < 0xDC00)
198+
if (p_rtl)
199+
t_char = MCStringGetCharAtIndex(p_text, t_end - t_index - t_offset);
200+
else
201+
t_char = MCStringGetCharAtIndex(p_text, t_offset + t_index);
202+
203+
if (MCUnicodeCodepointIsHighSurrogate(t_char))
196204
{
197205
// Surrogate pair
198-
t_char = ((t_char - 0xD800) << 10) + (MCStringGetCharAtIndex(p_text, t_offset + t_index + 1) - 0xDC00);
206+
if (p_rtl)
207+
t_char = MCUnicodeSurrogatesToCodepoint(t_char, MCStringGetCharAtIndex(p_text, t_end - t_index - t_offset - 1));
208+
else
209+
t_char = MCUnicodeSurrogatesToCodepoint(t_char, MCStringGetCharAtIndex(p_text, t_offset + t_index + 1));
210+
199211
t_advance = 2;
200212
}
201213
else
@@ -253,7 +265,10 @@ void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFo
253265

254266
// Process this chunk of text
255267
MCRange t_range;
256-
t_range = MCRangeMake(t_offset, t_break_point);
268+
if (p_rtl)
269+
t_range = MCRangeMake(t_end - t_offset - t_break_point, t_break_point);
270+
else
271+
t_range = MCRangeMake(t_offset, t_break_point);
257272
p_callback(p_font, p_text, t_range, p_callback_data);
258273

259274
// Explicitly show breaking points
@@ -292,7 +307,7 @@ int32_t MCFontMeasureTextSubstring(MCFontRef p_font, MCStringRef p_string, MCRan
292307
font_measure_text_context ctxt;
293308
ctxt.m_width = 0;
294309

295-
MCFontBreakText(p_font, p_string, p_range, (MCFontBreakTextCallback)MCFontMeasureTextCallback, &ctxt);
310+
MCFontBreakText(p_font, p_string, p_range, (MCFontBreakTextCallback)MCFontMeasureTextCallback, &ctxt, false);
296311

297312
return ctxt . m_width;
298313
}
@@ -302,6 +317,7 @@ struct font_draw_text_context
302317
MCGContextRef m_gcontext;
303318
int32_t x;
304319
int32_t y;
320+
bool rtl;
305321
};
306322

307323
static void MCFontDrawTextCallback(MCFontRef p_font, MCStringRef p_text, MCRange p_range, font_draw_text_context *ctxt)
@@ -311,26 +327,27 @@ static void MCFontDrawTextCallback(MCFontRef p_font, MCStringRef p_text, MCRange
311327

312328
// The drawing is done on the UTF-16 form of the text
313329

314-
MCGContextDrawPlatformText(ctxt->m_gcontext, MCStringGetCharPtr(p_text) + p_range.offset, p_range.length*2, MCGPointMake(ctxt->x, ctxt->y), t_font);
330+
MCGContextDrawPlatformText(ctxt->m_gcontext, MCStringGetCharPtr(p_text) + p_range.offset, p_range.length*2, MCGPointMake(ctxt->x, ctxt->y), t_font, ctxt->rtl);
315331

316332
// The draw position needs to be advanced
317333
ctxt -> x += MCGContextMeasurePlatformText(NULL, MCStringGetCharPtr(p_text) + p_range.offset, p_range.length*2, t_font);
318334
}
319335

320-
void MCFontDrawText(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCFontRef font)
336+
void MCFontDrawText(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCFontRef font, bool p_rtl)
321337
{
322338
MCRange t_range = MCRangeMake(0, MCStringGetLength(p_text));
323-
return MCFontDrawTextSubstring(p_gcontext, x, y, p_text, t_range, font);
339+
return MCFontDrawTextSubstring(p_gcontext, x, y, p_text, t_range, font, p_rtl);
324340
}
325341

326-
void MCFontDrawTextSubstring(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCRange p_range, MCFontRef p_font)
342+
void MCFontDrawTextSubstring(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCRange p_range, MCFontRef p_font, bool p_rtl)
327343
{
328344
font_draw_text_context ctxt;
329345
ctxt.x = x;
330346
ctxt.y = y;
331347
ctxt.m_gcontext = p_gcontext;
348+
ctxt.rtl = p_rtl;
332349

333-
MCFontBreakText(p_font, p_text, p_range, (MCFontBreakTextCallback)MCFontDrawTextCallback, &ctxt);
350+
MCFontBreakText(p_font, p_text, p_range, (MCFontBreakTextCallback)MCFontDrawTextCallback, &ctxt, p_rtl);
334351
}
335352

336353
MCFontStyle MCFontStyleFromTextStyle(uint2 p_text_style)

engine/src/font.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ int32_t MCFontGetAscent(MCFontRef font);
5252
int32_t MCFontGetDescent(MCFontRef font);
5353

5454
typedef void (*MCFontBreakTextCallback)(MCFontRef font, MCStringRef p_text, MCRange p_range, void *ctxt);
55-
void MCFontBreakText(MCFontRef font, MCStringRef p_text, MCRange p_range, MCFontBreakTextCallback callback, void *callback_data);
55+
void MCFontBreakText(MCFontRef font, MCStringRef p_text, MCRange p_range, MCFontBreakTextCallback callback, void *callback_data, bool p_rtl);
5656

5757
int32_t MCFontMeasureText(MCFontRef font, MCStringRef p_text);
5858
int32_t MCFontMeasureTextSubstring(MCFontRef font, MCStringRef p_text, MCRange p_range);
5959

6060
void MCFontDrawText(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCFontRef font);
61-
void MCFontDrawTextSubstring(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCRange p_range, MCFontRef font);
61+
void MCFontDrawTextSubstring(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCRange p_range, MCFontRef font, bool p_rtl);
6262

6363
MCFontStyle MCFontStyleFromTextStyle(uint2 text_style);
6464
uint16_t MCFontStyleToTextStyle(MCFontStyle font_style);

0 commit comments

Comments
 (0)