Files
freetype/test/arabic.c
2023-08-27 18:03:45 +02:00

387 lines
9.6 KiB
C

/****************************************************************************/
/* */
/* The FreeType project -- a free and portable quality TrueType renderer. */
/* */
/* Copyright 1996-1999 by */
/* D. Turner, R.Wilhelm, and W. Lemberg */
/* */
/* arabic -- An implementation of the contextual algorithm given in the */
/* Unicode 2.0 book to assign the `isolated', `initial', `medial', and */
/* `final' properties to an input string of character codes for the Arabic */
/* script. */
/* */
/****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "arabic.h"
#include "freetype.h"
#include "ftxopen.h"
/*
Here a table of the joining classes for characters in the range
U+0620 - U+06FF.
The following character also has a joining class:
U+200C ZERO WIDTH NON-JOINER -> causing
All other characters are given the joining class `none'.
*/
joining_class arabic[] =
{
/* U+0620 */
none, none, right, right,
right, right, dual, right,
dual, right, dual, dual,
dual, dual, dual, right,
/* U+0630 */
right, right, right, dual,
dual, dual, dual, dual,
dual, dual, dual, none,
none, none, none, none,
/* U+0640 */
causing, dual, dual, dual,
dual, dual, dual, dual,
right, right, dual, transparent,
transparent, transparent, transparent, transparent,
/* U+0650 */
transparent, transparent, transparent, none,
none, none, none, none,
none, none, none, none,
none, none, none, none,
/* U+0660 */
none, none, none, none,
none, none, none, none,
none, none, none, none,
none, none, none, none,
/* U+0670 */
transparent, none, right, right,
none, right, right, right,
dual, dual, dual, dual,
dual, dual, dual, dual,
/* U+0680 */
dual, dual, dual, dual,
dual, dual, dual, dual,
right, right, right, right,
right, right, right, right,
/* U+0690 */
right, right, right, right,
right, right, right, right,
right, right, dual, dual,
dual, dual, dual, dual,
/* U+06A0 */
dual, dual, dual, dual,
dual, dual, dual, dual,
dual, dual, dual, dual,
dual, dual, dual, dual,
/* U+06B0 */
dual, dual, dual, dual,
dual, dual, dual, dual,
dual, dual, dual, dual,
dual, dual, dual, dual,
/* U+06C0 */
right, dual, right, right,
right, right, right, right,
right, right, right, right,
dual, right, dual, right,
/* U+06D0 */
dual, dual, right, right,
none, none, none, transparent,
transparent, transparent, transparent, transparent,
transparent, transparent, transparent, transparent,
/* U+06E0 */
transparent, transparent, transparent, transparent,
transparent, none, none, transparent,
transparent, none, transparent, transparent,
transparent, transparent, none, none,
/* U+06F0 */
none, none, none, none,
none, none, none, none,
none, none, dual, dual,
dual, none, none, none
};
struct cgc_
{
TT_UShort char_code;
TT_UShort glyph_index;
TT_UShort class;
};
typedef struct cgc_ cgc;
int compare_cgc( const void* a,
const void* b )
{
return ( ((cgc*)a)->glyph_index > ((cgc*)b)->glyph_index ) ?
1 : ( ( ((cgc*)a)->glyph_index == ((cgc*)b)->glyph_index ) ?
0 : -1 );
}
TT_Error Build_Arabic_Glyph_Properties( TT_CharMap char_map,
TT_UShort max_glyphs,
TTO_GDEFHeader** gdef )
{
TT_UShort i, j, num_glyphs;
cgc Arabic[0x0700 - 0x0620];
TT_UShort glyph_indices[0x700 - 0x0620];
TT_UShort classes[0x700 - 0x0620];
if ( !gdef )
return TT_Err_Invalid_Argument;
j = 0;
for ( i = 0x0620; i < 0x0700; i++ )
{
Arabic[j].char_code = i;
Arabic[j].class = ( arabic[i - 0x0620] == transparent ) ?
MARK_GLYPH : SIMPLE_GLYPH;
Arabic[j].glyph_index = TT_Char_Index( char_map, i );
if ( Arabic[j].glyph_index )
j++;
}
num_glyphs = j;
if ( !num_glyphs )
{
/* no Arabic font */
*gdef = NULL;
return TT_Err_Ok;
}
/* sort it */
qsort( Arabic, num_glyphs, sizeof ( cgc ), compare_cgc );
/* write it to the arrays, removing duplicates */
glyph_indices[0] = Arabic[0].glyph_index;
classes[0] = Arabic[0].class;
j = 1;
for ( i = 1; i < num_glyphs; i++ )
{
glyph_indices[j] = Arabic[i].glyph_index;
classes[j] = Arabic[i].class;
if ( glyph_indices[j - 1] != glyph_indices[j] )
j++;
}
num_glyphs = j;
TT_GDEF_Build_ClassDefinition( *gdef, max_glyphs, num_glyphs,
glyph_indices, classes );
return TT_Err_Ok;
}
/* The joining rules as given in the Unicode 2.0 book (characters are
here specified as appearing in the byte stream, i.e. *not* in
visual order). Joining classes are given in angle brackets, glyph
forms in square brackets. Glyphs affected by a specific rule are
enclosed with vertical bars.
Note: The description of the joining algorithm in the book is
severely broken. You can get a corrected version from
www.unicode.org (as of 29-Jun-1999, this hasn't appeared).
R1: <anything1> <transparent> <anything2>
apply joining rules for
<anything1> <anything2> -> [shape1] [shape2]
-> [shape1] [isolated] [shape2]
R2: <causing|left|dual> |<right>|
-> [final]
R3: |<left>| <causing|right|dual>
-> [initial]
R4: <causing|left|dual> |<dual>| <causing|right|dual>
-> [medial]
R5: <causing|left|dual> |<dual>| <!(causing|right|dual)>
-> [final]
R6: <!(causing|left|dual)> |<dual>| <causing|right|dual>
-> [initial]
R7: If R1-R6 fail:
<anything> -> [isolated] */
/* `direction' can be -1, 0, or 1 to indicate the last non-transparent
glyph, the current glyph, and the next non-transparent glyph,
respectively. */
static joining_class Get_Joining_Class( TT_UShort* string,
TT_UShort pos,
TT_UShort length,
int direction )
{
joining_class j;
while ( 1 )
{
if ( pos == 0 && direction < 0 )
return none;
pos += direction;
if ( pos >= length )
return none;
if ( string[pos] < 0x0620 ||
string[pos] >= 0x0700 )
{
if ( string[pos] == 0x200C )
return causing;
else
return none;
}
else
j = arabic[string[pos] - 0x0620];
if ( !direction || j != transparent )
return j;
}
}
TT_Error Assign_Arabic_Properties( TT_UShort* string,
TT_UShort* properties,
TT_UShort length )
{
joining_class previous, current, next;
TT_UShort i;
if ( !string || !properties || length == 0 )
return TT_Err_Invalid_Argument;
for ( i = 0; i < length; i++ )
{
previous = Get_Joining_Class( string, i, length, -1 );
current = Get_Joining_Class( string, i, length, 0 );
next = Get_Joining_Class( string, i, length, 1 );
/* R1 */
if ( current == transparent )
{
properties[i] |= isolated_p;
continue;
}
/* R2 */
if ( previous == causing ||
previous == left ||
previous == dual )
if ( current == right )
{
properties[i] |= final_p;
continue;
}
/* R3 */
if ( current == left )
if ( next == causing ||
next == right ||
next == dual )
{
properties[i] |= initial_p;
continue;
}
/* R4 */
if ( previous == causing ||
previous == left ||
previous == dual )
if ( current == dual )
if ( next == causing ||
next == right ||
next == dual )
{
properties[i] |= medial_p;
continue;
}
/* R5 */
if ( previous == causing ||
previous == left ||
previous == dual )
if ( current == dual )
if ( !( next == causing ||
next == right ||
next == dual ) )
{
properties[i] |= final_p;
continue;
}
/* R6 */
if ( !( previous == causing ||
previous == left ||
previous == dual ) )
if ( current == dual )
if ( next == causing ||
next == right ||
next == dual )
{
properties[i] |= initial_p;
continue;
}
/* R7 */
if ( current != none )
properties[i] |= isolated_p;
}
return TT_Err_Ok;
}
/* End */