<s> """<STR_LIT>""" <EOL> __author__ = '<STR_LIT>' <EOL> import json <EOL> import os <EOL> import subprocess <EOL> import font_caching <EOL> def min_with_none ( first , second ) : <EOL> """<STR_LIT>""" <EOL> if first is None : <EOL> return second <EOL> elif second is None : <EOL> return first <EOL> else : <EOL> return min ( first , second ) <EOL> def max_with_none ( first , second ) : <EOL> """<STR_LIT>""" <EOL> if first is None : <EOL> return second <EOL> elif second is None : <EOL> return first <EOL> else : <EOL> return max ( first , second ) <EOL> def transform_y ( transform , y_value ) : <EOL> """<STR_LIT>""" <EOL> return int ( round ( y_value * transform [ <NUM_LIT:1> ] [ <NUM_LIT:1> ] ) ) <EOL> def get_glyph_cleaned_extents ( glyph , glyf_table ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> return glyph . cleanedYMin , glyph . cleanedYMax <EOL> except AttributeError : <EOL> glyph . expand ( glyf_table ) <EOL> if glyph . numberOfContours == <NUM_LIT:0> : <EOL> glyph . cleanedYMin = None <EOL> glyph . cleanedYMax = None <EOL> return None , None <EOL> elif glyph . numberOfContours == - <NUM_LIT:1> : <EOL> max_height = None <EOL> min_height = None <EOL> for component in glyph . components : <EOL> component_ymin , component_ymax = get_glyph_cleaned_extents ( <EOL> glyf_table . glyphs [ component . glyphName ] , <EOL> glyf_table ) <EOL> if hasattr ( component , '<STR_LIT>' ) : <EOL> transform = component . transform <EOL> assert transform [ <NUM_LIT:1> ] [ <NUM_LIT:0> ] == transform [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] == <NUM_LIT:0> , ( <EOL> "<STR_LIT>" ) <EOL> else : <EOL> transform = [ [ <NUM_LIT:1> , <NUM_LIT:0> ] , [ <NUM_LIT:0> , <NUM_LIT:1> ] ] <EOL> max_height = max_with_none ( <EOL> max_height , <EOL> transform_y ( transform , component_ymax ) + component . y ) <EOL> min_height = min_with_none ( <EOL> min_height , <EOL> transform_y ( transform , component_ymin ) + component . y ) <EOL> else : <EOL> points_to_ignore = set ( ) <EOL> previous_end_point = - <NUM_LIT:1> <EOL> for end_point in glyph . endPtsOfContours : <EOL> if end_point == previous_end_point + <NUM_LIT:1> : <EOL> points_to_ignore . add ( end_point ) <EOL> previous_end_point = end_point <EOL> max_height = None <EOL> min_height = None <EOL> for index , point in enumerate ( glyph . coordinates ) : <EOL> if index in points_to_ignore : <EOL> continue <EOL> y_value = point [ <NUM_LIT:1> ] <EOL> max_height = max_with_none ( max_height , y_value ) <EOL> min_height = min_with_none ( min_height , y_value ) <EOL> glyph . cleanedYMin = min_height <EOL> glyph . cleanedYMax = max_height <EOL> return min_height , max_height <EOL> def get_glyph_vertical_extents ( glyph_id , font_file_name ) : <EOL> """<STR_LIT>""" <EOL> font = font_caching . open_font ( font_file_name ) <EOL> glyf_table = font [ '<STR_LIT>' ] <EOL> glyph_name = glyf_table . getGlyphName ( glyph_id ) <EOL> glyph = glyf_table . glyphs [ glyph_name ] <EOL> return get_glyph_cleaned_extents ( glyph , glyf_table ) <EOL> HARFBUZZ_DIR = os . getenv ( '<STR_LIT>' ) + os . sep + '<STR_LIT>' <EOL> HB_SHAPE_PATH = HARFBUZZ_DIR + os . sep + '<STR_LIT>' + os . sep + '<STR_LIT>' <EOL> def run_harfbuzz_on_text ( text , font_file_name , language , extra_parameters = None ) : <EOL> """<STR_LIT>""" <EOL> hb_parameters = [ <EOL> HB_SHAPE_PATH , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' % font_file_name ] <EOL> if language : <EOL> hb_parameters . append ( '<STR_LIT>' % language ) <EOL> if extra_parameters is not None : <EOL> hb_parameters += extra_parameters <EOL> hb_process = subprocess . Popen ( <EOL> hb_parameters , <EOL> stdin = subprocess . PIPE , <EOL> stdout = subprocess . PIPE ) <EOL> return hb_process . communicate ( input = text . encode ( '<STR_LIT>' ) ) [ <NUM_LIT:0> ] <EOL> def get_line_extents_from_json ( json_data , font_file_name ) : <EOL> """<STR_LIT>""" <EOL> max_height = None <EOL> min_height = None <EOL> for glyph_position in json . loads ( json_data ) : <EOL> glyph_id = glyph_position [ '<STR_LIT:g>' ] <EOL> glyph_ymin , glyph_ymax = get_glyph_vertical_extents ( <EOL> glyph_id , font_file_name ) <EOL> if glyph_ymax is not None : <EOL> glyph_vertical_offset = glyph_position [ '<STR_LIT>' ] <EOL> max_height = max_with_none ( <EOL> max_height , glyph_ymax + glyph_vertical_offset ) <EOL> min_height = min_with_none ( <EOL> min_height , glyph_ymin + glyph_vertical_offset ) <EOL> return min_height , max_height <EOL> def test_text_vertical_extents ( <EOL> text , font_file_name , min_allowed , max_allowed , language = None ) : <EOL> """<STR_LIT>""" <EOL> hb_output = run_harfbuzz_on_text ( text , font_file_name , language ) <EOL> split_text = text . split ( '<STR_LIT:\n>' ) <EOL> exceeding_lines = [ ] <EOL> for line_no , output_line in enumerate ( hb_output . split ( '<STR_LIT:\n>' ) ) : <EOL> if not output_line : <EOL> continue <EOL> min_height , max_height = get_line_extents_from_json ( <EOL> output_line , font_file_name ) <EOL> if min_height is None : <EOL> continue <EOL> if min_height < min_allowed or max_height > max_allowed : <EOL> exceeding_lines . append ( ( ( min_height , max_height ) , <EOL> split_text [ line_no ] ) ) <EOL> return exceeding_lines </s>
