2013-02-11 19:36:23 +01:00
/*
* Copyright © 2011 , 2012 , 2013 Google , Inc .
*
* This is part of HarfBuzz , a text shaping library .
*
* Permission is hereby granted , without written agreement and without
* license or royalty fees , to use , copy , modify , and distribute this
* software and its documentation for any purpose , provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software .
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT , INDIRECT , SPECIAL , INCIDENTAL , OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION , EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE .
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES , INCLUDING ,
* BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE . THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN " AS IS " BASIS , AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE , SUPPORT , UPDATES , ENHANCEMENTS , OR MODIFICATIONS .
*
* Google Author ( s ) : Behdad Esfahbod
*/
2019-06-26 22:21:03 +02:00
# include "hb.hh"
# ifndef HB_NO_OT_SHAPE
2022-06-03 10:56:41 +02:00
# include "hb-ot-shaper-myanmar-machine.hh"
2022-06-05 09:52:31 +02:00
# include "hb-ot-shaper-indic.hh"
# include "hb-ot-layout.hh"
2013-02-11 19:36:23 +01:00
/*
* Myanmar shaper .
*/
2022-06-10 08:50:47 +02:00
2013-02-11 19:36:23 +01:00
static const hb_tag_t
2019-07-03 00:09:26 +02:00
myanmar_basic_features [ ] =
2013-02-11 19:36:23 +01:00
{
/*
* Basic features .
2021-08-03 18:11:27 +02:00
* These features are applied in order , one at a time , after reordering ,
* constrained to the syllable .
2013-02-11 19:36:23 +01:00
*/
HB_TAG ( ' r ' , ' p ' , ' h ' , ' f ' ) ,
HB_TAG ( ' p ' , ' r ' , ' e ' , ' f ' ) ,
HB_TAG ( ' b ' , ' l ' , ' w ' , ' f ' ) ,
HB_TAG ( ' p ' , ' s ' , ' t ' , ' f ' ) ,
2013-02-15 12:22:26 +01:00
} ;
static const hb_tag_t
2019-07-03 00:09:26 +02:00
myanmar_other_features [ ] =
2013-02-15 12:22:26 +01:00
{
2013-02-11 19:36:23 +01:00
/*
* Other features .
2018-10-27 00:40:12 +02:00
* These features are applied all at once , after clearing syllables .
2013-02-11 19:36:23 +01:00
*/
HB_TAG ( ' p ' , ' r ' , ' e ' , ' s ' ) ,
HB_TAG ( ' a ' , ' b ' , ' v ' , ' s ' ) ,
HB_TAG ( ' b ' , ' l ' , ' w ' , ' s ' ) ,
HB_TAG ( ' p ' , ' s ' , ' t ' , ' s ' ) ,
2018-09-24 04:33:38 +02:00
} ;
2013-02-11 19:36:23 +01:00
2022-06-05 09:52:31 +02:00
static inline void
set_myanmar_properties ( hb_glyph_info_t & info )
{
hb_codepoint_t u = info . codepoint ;
unsigned int type = hb_indic_get_categories ( u ) ;
2022-06-10 00:43:50 +02:00
info . myanmar_category ( ) = ( myanmar_category_t ) ( type & 0xFFu ) ;
2022-06-05 09:52:31 +02:00
}
2022-06-10 14:34:56 +02:00
static inline bool
is_one_of_myanmar ( const hb_glyph_info_t & info , unsigned int flags )
{
/* If it ligated, all bets are off. */
if ( _hb_glyph_info_ligated ( & info ) ) return false ;
2022-06-11 11:53:47 +02:00
return ! ! ( FLAG_UNSAFE ( info . myanmar_category ( ) ) & flags ) ;
2022-06-10 14:34:56 +02:00
}
/* Note:
*
* We treat Vowels and placeholders as if they were consonants . This is safe because Vowels
* cannot happen in a consonant syllable . The plus side however is , we can call the
* consonant syllable logic from the vowel syllable function and get it all right !
*
* Keep in sync with consonant_categories in the generator . */
# define CONSONANT_FLAGS_MYANMAR (FLAG (M_Cat(C)) | FLAG (M_Cat(CS)) | FLAG (M_Cat(Ra)) | /* FLAG (M_Cat(CM)) | */ FLAG (M_Cat(IV)) | FLAG (M_Cat(GB)) | FLAG (M_Cat(DOTTEDCIRCLE)))
static inline bool
is_consonant_myanmar ( const hb_glyph_info_t & info )
{
return is_one_of_myanmar ( info , CONSONANT_FLAGS_MYANMAR ) ;
}
2022-11-17 01:49:44 +01:00
static bool
2019-07-02 23:42:45 +02:00
setup_syllables_myanmar ( const hb_ot_shape_plan_t * plan ,
hb_font_t * font ,
hb_buffer_t * buffer ) ;
2022-11-17 01:49:44 +01:00
static bool
2019-07-02 23:42:45 +02:00
reorder_myanmar ( const hb_ot_shape_plan_t * plan ,
2018-10-27 00:40:12 +02:00
hb_font_t * font ,
hb_buffer_t * buffer ) ;
2013-02-11 19:36:23 +01:00
static void
collect_features_myanmar ( hb_ot_shape_planner_t * plan )
{
hb_ot_map_builder_t * map = & plan - > map ;
/* Do this before any lookups have been applied. */
2019-07-02 23:42:45 +02:00
map - > add_gsub_pause ( setup_syllables_myanmar ) ;
2013-02-11 19:36:23 +01:00
2022-03-28 20:38:56 +02:00
map - > enable_feature ( HB_TAG ( ' l ' , ' o ' , ' c ' , ' l ' ) , F_PER_SYLLABLE ) ;
2013-02-11 19:36:23 +01:00
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it , it ' s typically at the beginning . */
2022-03-28 20:38:56 +02:00
map - > enable_feature ( HB_TAG ( ' c ' , ' c ' , ' m ' , ' p ' ) , F_PER_SYLLABLE ) ;
2013-02-11 19:36:23 +01:00
2019-07-02 23:42:45 +02:00
map - > add_gsub_pause ( reorder_myanmar ) ;
2018-09-24 04:33:38 +02:00
2019-07-03 00:09:26 +02:00
for ( unsigned int i = 0 ; i < ARRAY_LENGTH ( myanmar_basic_features ) ; i + + )
2013-02-15 12:22:26 +01:00
{
2022-03-28 20:38:56 +02:00
map - > enable_feature ( myanmar_basic_features [ i ] , F_MANUAL_ZWJ | F_PER_SYLLABLE ) ;
2017-10-15 12:11:08 +02:00
map - > add_gsub_pause ( nullptr ) ;
2013-02-11 19:36:23 +01:00
}
2022-06-04 18:55:50 +02:00
map - > add_gsub_pause ( hb_syllabic_clear_var ) ; // Don't need syllables anymore, use stop to free buffer var
2018-09-24 04:33:38 +02:00
2019-07-03 00:09:26 +02:00
for ( unsigned int i = 0 ; i < ARRAY_LENGTH ( myanmar_other_features ) ; i + + )
map - > enable_feature ( myanmar_other_features [ i ] , F_MANUAL_ZWJ ) ;
2013-02-11 19:36:23 +01:00
}
static void
setup_masks_myanmar ( const hb_ot_shape_plan_t * plan HB_UNUSED ,
2019-10-01 12:19:55 +02:00
hb_buffer_t * buffer ,
hb_font_t * font HB_UNUSED )
2013-02-11 19:36:23 +01:00
{
HB_BUFFER_ALLOCATE_VAR ( buffer , myanmar_category ) ;
HB_BUFFER_ALLOCATE_VAR ( buffer , myanmar_position ) ;
2022-04-20 17:56:34 +02:00
/* No masks, we just save information about characters. */
2013-02-11 19:36:23 +01:00
unsigned int count = buffer - > len ;
2014-07-17 20:22:11 +02:00
hb_glyph_info_t * info = buffer - > info ;
2013-02-11 19:36:23 +01:00
for ( unsigned int i = 0 ; i < count ; i + + )
2014-07-17 20:22:11 +02:00
set_myanmar_properties ( info [ i ] ) ;
2013-02-11 19:36:23 +01:00
}
2022-11-17 01:49:44 +01:00
static bool
2019-07-02 23:42:45 +02:00
setup_syllables_myanmar ( const hb_ot_shape_plan_t * plan HB_UNUSED ,
hb_font_t * font HB_UNUSED ,
hb_buffer_t * buffer )
2013-02-11 19:36:23 +01:00
{
2022-06-04 18:55:50 +02:00
HB_BUFFER_ALLOCATE_VAR ( buffer , syllable ) ;
2019-07-02 23:42:45 +02:00
find_syllables_myanmar ( buffer ) ;
2017-08-11 03:45:33 +02:00
foreach_syllable ( buffer , start , end )
buffer - > unsafe_to_break ( start , end ) ;
2022-11-17 01:49:44 +01:00
return false ;
2013-02-11 19:36:23 +01:00
}
static int
compare_myanmar_order ( const hb_glyph_info_t * pa , const hb_glyph_info_t * pb )
{
int a = pa - > myanmar_position ( ) ;
int b = pb - > myanmar_position ( ) ;
2022-06-10 15:12:39 +02:00
return ( int ) a - ( int ) b ;
2013-02-11 19:36:23 +01:00
}
/* Rules from:
2018-04-12 11:10:45 +02:00
* https : //docs.microsoft.com/en-us/typography/script-development/myanmar */
2013-02-11 19:36:23 +01:00
static void
2015-07-22 12:58:11 +02:00
initial_reordering_consonant_syllable ( hb_buffer_t * buffer ,
2013-02-11 19:36:23 +01:00
unsigned int start , unsigned int end )
{
hb_glyph_info_t * info = buffer - > info ;
unsigned int base = end ;
bool has_reph = false ;
{
unsigned int limit = start ;
if ( start + 3 < = end & &
2022-06-05 09:52:31 +02:00
info [ start ] . myanmar_category ( ) = = M_Cat ( Ra ) & &
info [ start + 1 ] . myanmar_category ( ) = = M_Cat ( As ) & &
info [ start + 2 ] . myanmar_category ( ) = = M_Cat ( H ) )
2013-02-11 19:36:23 +01:00
{
limit + = 3 ;
base = start ;
has_reph = true ;
}
{
if ( ! has_reph )
base = limit ;
for ( unsigned int i = limit ; i < end ; i + + )
2022-06-10 14:34:56 +02:00
if ( is_consonant_myanmar ( info [ i ] ) )
2013-02-11 19:36:23 +01:00
{
base = i ;
break ;
}
}
}
/* Reorder! */
{
unsigned int i = start ;
for ( ; i < start + ( has_reph ? 3 : 0 ) ; i + + )
info [ i ] . myanmar_position ( ) = POS_AFTER_MAIN ;
for ( ; i < base ; i + + )
info [ i ] . myanmar_position ( ) = POS_PRE_C ;
if ( i < end )
{
info [ i ] . myanmar_position ( ) = POS_BASE_C ;
i + + ;
}
2021-09-20 19:33:01 +02:00
myanmar_position_t pos = POS_AFTER_MAIN ;
2013-02-11 19:36:23 +01:00
/* The following loop may be ugly, but it implements all of
* Myanmar reordering ! */
for ( ; i < end ; i + + )
{
2022-06-05 09:52:31 +02:00
if ( info [ i ] . myanmar_category ( ) = = M_Cat ( MR ) ) /* Pre-base reordering */
2013-02-11 19:36:23 +01:00
{
info [ i ] . myanmar_position ( ) = POS_PRE_C ;
continue ;
}
2022-06-09 21:04:28 +02:00
if ( info [ i ] . myanmar_category ( ) = = M_Cat ( VPre ) ) /* Left matra */
2013-02-11 19:36:23 +01:00
{
2022-06-09 21:04:28 +02:00
info [ i ] . myanmar_position ( ) = POS_PRE_M ;
2013-02-11 19:36:23 +01:00
continue ;
}
2022-06-05 09:52:31 +02:00
if ( info [ i ] . myanmar_category ( ) = = M_Cat ( VS ) )
2018-02-02 18:04:04 +01:00
{
info [ i ] . myanmar_position ( ) = info [ i - 1 ] . myanmar_position ( ) ;
continue ;
}
2013-02-11 19:36:23 +01:00
2022-06-05 09:52:31 +02:00
if ( pos = = POS_AFTER_MAIN & & info [ i ] . myanmar_category ( ) = = M_Cat ( VBlw ) )
2013-02-11 19:36:23 +01:00
{
pos = POS_BELOW_C ;
info [ i ] . myanmar_position ( ) = pos ;
continue ;
}
2022-06-05 09:52:31 +02:00
if ( pos = = POS_BELOW_C & & info [ i ] . myanmar_category ( ) = = M_Cat ( A ) )
2013-02-11 19:36:23 +01:00
{
info [ i ] . myanmar_position ( ) = POS_BEFORE_SUB ;
continue ;
}
2022-06-05 09:52:31 +02:00
if ( pos = = POS_BELOW_C & & info [ i ] . myanmar_category ( ) = = M_Cat ( VBlw ) )
2013-02-11 19:36:23 +01:00
{
info [ i ] . myanmar_position ( ) = pos ;
continue ;
}
2022-06-05 09:52:31 +02:00
if ( pos = = POS_BELOW_C & & info [ i ] . myanmar_category ( ) ! = M_Cat ( A ) )
2013-02-11 19:36:23 +01:00
{
2019-08-24 15:27:14 +02:00
pos = POS_AFTER_SUB ;
2013-02-11 19:36:23 +01:00
info [ i ] . myanmar_position ( ) = pos ;
continue ;
}
info [ i ] . myanmar_position ( ) = pos ;
}
}
/* Sit tight, rock 'n roll! */
2015-09-01 17:15:25 +02:00
buffer - > sort ( start , end , compare_myanmar_order ) ;
2022-11-04 23:00:34 +01:00
/* Flip left-matra sequence. */
unsigned first_left_matra = end ;
unsigned last_left_matra = end ;
for ( unsigned int i = start ; i < end ; i + + )
{
if ( info [ i ] . myanmar_position ( ) = = POS_PRE_M )
{
if ( first_left_matra = = end )
first_left_matra = i ;
last_left_matra = i ;
}
}
/* https://github.com/harfbuzz/harfbuzz/issues/3863 */
if ( first_left_matra < last_left_matra )
{
/* No need to merge clusters, done already? */
buffer - > reverse_range ( first_left_matra , last_left_matra + 1 ) ;
/* Reverse back VS, etc. */
unsigned i = first_left_matra ;
for ( unsigned j = i ; j < = last_left_matra ; j + + )
if ( info [ j ] . myanmar_category ( ) = = M_Cat ( VPre ) )
{
buffer - > reverse_range ( i , j + 1 ) ;
i = j + 1 ;
}
}
2013-02-11 19:36:23 +01:00
}
static void
2019-07-03 00:09:26 +02:00
reorder_syllable_myanmar ( const hb_ot_shape_plan_t * plan HB_UNUSED ,
hb_face_t * face HB_UNUSED ,
hb_buffer_t * buffer ,
unsigned int start , unsigned int end )
2013-02-11 19:36:23 +01:00
{
2019-07-02 23:42:45 +02:00
myanmar_syllable_type_t syllable_type = ( myanmar_syllable_type_t ) ( buffer - > info [ start ] . syllable ( ) & 0x0F ) ;
2013-02-11 19:36:23 +01:00
switch ( syllable_type ) {
2015-07-22 12:58:11 +02:00
2019-07-02 23:42:45 +02:00
case myanmar_broken_cluster : /* We already inserted dotted-circles, so just call the consonant_syllable. */
case myanmar_consonant_syllable :
2015-07-22 12:58:11 +02:00
initial_reordering_consonant_syllable ( buffer , start , end ) ;
break ;
2019-07-02 23:42:45 +02:00
case myanmar_non_myanmar_cluster :
2015-07-22 12:58:11 +02:00
break ;
2013-02-11 19:36:23 +01:00
}
}
2022-11-17 01:49:44 +01:00
static bool
2019-07-02 23:42:45 +02:00
reorder_myanmar ( const hb_ot_shape_plan_t * plan ,
hb_font_t * font ,
hb_buffer_t * buffer )
2013-02-11 19:36:23 +01:00
{
2022-11-17 01:49:44 +01:00
bool ret = false ;
2021-01-16 03:13:47 +01:00
if ( buffer - > message ( font , " start reordering myanmar " ) )
{
2022-11-17 01:49:44 +01:00
if ( hb_syllabic_insert_dotted_circles ( font , buffer ,
myanmar_broken_cluster ,
M_Cat ( DOTTEDCIRCLE ) ) )
ret = true ;
2013-02-11 19:36:23 +01:00
2020-09-17 15:25:30 +02:00
foreach_syllable ( buffer , start , end )
reorder_syllable_myanmar ( plan , font - > face , buffer , start , end ) ;
2020-09-18 17:24:47 +02:00
( void ) buffer - > message ( font , " end reordering myanmar " ) ;
2020-09-17 15:25:30 +02:00
}
2018-10-27 00:40:12 +02:00
HB_BUFFER_DEALLOCATE_VAR ( buffer , myanmar_category ) ;
HB_BUFFER_DEALLOCATE_VAR ( buffer , myanmar_position ) ;
2022-11-17 01:49:44 +01:00
return ret ;
2013-02-11 19:36:23 +01:00
}
2013-10-28 00:20:59 +01:00
2022-06-03 10:42:34 +02:00
const hb_ot_shaper_t _hb_ot_shaper_myanmar =
2014-07-27 01:17:44 +02:00
{
2018-10-12 02:15:31 +02:00
collect_features_myanmar ,
2020-09-12 21:17:18 +02:00
nullptr , /* override_features */
2017-10-15 12:11:08 +02:00
nullptr , /* data_create */
nullptr , /* data_destroy */
nullptr , /* preprocess_text */
nullptr , /* postprocess_glyphs */
nullptr , /* decompose */
nullptr , /* compose */
2018-10-12 02:15:31 +02:00
setup_masks_myanmar ,
2017-10-15 12:11:08 +02:00
nullptr , /* reorder_marks */
2022-07-13 21:34:11 +02:00
HB_TAG_NONE , /* gpos_tag */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT ,
2018-10-12 02:15:31 +02:00
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY ,
false , /* fallback_position */
2014-07-27 01:17:44 +02:00
} ;
2018-10-12 02:15:31 +02:00
2022-11-24 20:46:04 +01:00
# ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
2018-10-12 02:20:00 +02:00
/* Ugly Zawgyi encoding.
* Disable all auto processing .
* https : //github.com/harfbuzz/harfbuzz/issues/1162 */
2022-06-03 10:42:34 +02:00
const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi =
2018-10-12 02:20:00 +02:00
{
nullptr , /* collect_features */
nullptr , /* override_features */
nullptr , /* data_create */
nullptr , /* data_destroy */
nullptr , /* preprocess_text */
nullptr , /* postprocess_glyphs */
nullptr , /* decompose */
nullptr , /* compose */
nullptr , /* setup_masks */
nullptr , /* reorder_marks */
2022-07-13 21:34:11 +02:00
HB_TAG_NONE , /* gpos_tag */
HB_OT_SHAPE_NORMALIZATION_MODE_NONE ,
2018-10-12 02:20:00 +02:00
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE ,
false , /* fallback_position */
} ;
2022-11-24 20:46:04 +01:00
# endif
2019-06-26 22:21:03 +02:00
# endif