<s> """<STR_LIT>""" <EOL> from __future__ import division <EOL> import pyphen <EOL> import cffi <EOL> import cairocffi as cairo <EOL> from . compat import basestring <EOL> ffi = cffi . FFI ( ) <EOL> ffi . cdef ( '''<STR_LIT>''' ) <EOL> def dlopen ( ffi , * names ) : <EOL> """<STR_LIT>""" <EOL> for name in names : <EOL> try : <EOL> return ffi . dlopen ( name ) <EOL> except OSError : <EOL> pass <EOL> return ffi . dlopen ( names [ <NUM_LIT:0> ] ) <EOL> gobject = dlopen ( ffi , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' ) <EOL> pango = dlopen ( ffi , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' ) <EOL> pangocairo = dlopen ( ffi , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' ) <EOL> gobject . g_type_init ( ) <EOL> units_to_double = pango . pango_units_to_double <EOL> units_from_double = pango . pango_units_from_double <EOL> PYPHEN_DICTIONARY_CACHE = { } <EOL> PANGO_STYLE = { <EOL> '<STR_LIT>' : pango . PANGO_STYLE_NORMAL , <EOL> '<STR_LIT>' : pango . PANGO_STYLE_OBLIQUE , <EOL> '<STR_LIT>' : pango . PANGO_STYLE_ITALIC , <EOL> } <EOL> PANGO_VARIANT = { <EOL> '<STR_LIT>' : pango . PANGO_VARIANT_NORMAL , <EOL> '<STR_LIT>' : pango . PANGO_VARIANT_SMALL_CAPS , <EOL> } <EOL> PANGO_STRETCH = { <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_ULTRA_CONDENSED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_EXTRA_CONDENSED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_CONDENSED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_SEMI_CONDENSED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_NORMAL , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_SEMI_EXPANDED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_EXPANDED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_EXTRA_EXPANDED , <EOL> '<STR_LIT>' : pango . PANGO_STRETCH_ULTRA_EXPANDED , <EOL> } <EOL> PANGO_WRAP_MODE = { <EOL> '<STR_LIT>' : pango . PANGO_WRAP_WORD , <EOL> '<STR_LIT>' : pango . PANGO_WRAP_CHAR , <EOL> '<STR_LIT>' : pango . PANGO_WRAP_WORD_CHAR <EOL> } <EOL> def utf8_slice ( string , slice_ ) : <EOL> return string . encode ( '<STR_LIT:utf-8>' ) [ slice_ ] . decode ( '<STR_LIT:utf-8>' ) <EOL> def unicode_to_char_p ( string ) : <EOL> """<STR_LIT>""" <EOL> bytestring = string . encode ( '<STR_LIT:utf8>' ) . replace ( b'<STR_LIT:\x00>' , b'<STR_LIT>' ) <EOL> return ffi . new ( '<STR_LIT>' , bytestring ) , bytestring <EOL> def get_size ( line ) : <EOL> logical_extents = ffi . new ( '<STR_LIT>' ) <EOL> pango . pango_layout_line_get_extents ( line , ffi . NULL , logical_extents ) <EOL> return ( units_to_double ( logical_extents . width ) , <EOL> units_to_double ( logical_extents . height ) ) <EOL> def get_ink_position ( line ) : <EOL> ink_extents = ffi . new ( '<STR_LIT>' ) <EOL> pango . pango_layout_line_get_extents ( line , ink_extents , ffi . NULL ) <EOL> return ( units_to_double ( ink_extents . x ) , units_to_double ( ink_extents . y ) ) <EOL> def first_line_metrics ( first_line , text , layout , resume_at , hyphenated = False ) : <EOL> length = first_line . length <EOL> if not hyphenated and resume_at : <EOL> first_line_text = utf8_slice ( text , slice ( length ) ) . rstrip ( '<STR_LIT:U+0020>' ) <EOL> layout . set_text ( first_line_text ) <EOL> first_line = next ( layout . iter_lines ( ) , None ) <EOL> length = first_line . length if first_line is not None else <NUM_LIT:0> <EOL> width , height = get_size ( first_line ) <EOL> baseline = units_to_double ( pango . pango_layout_iter_get_baseline ( ffi . gc ( <EOL> pango . pango_layout_get_iter ( layout . layout ) , <EOL> pango . pango_layout_iter_free ) ) ) <EOL> return layout , length , resume_at , width , height , baseline <EOL> class Layout ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , hinting , font_size , style ) : <EOL> self . dummy_context = ( <EOL> cairo . Context ( cairo . ImageSurface ( cairo . FORMAT_ARGB32 , <NUM_LIT:1> , <NUM_LIT:1> ) ) <EOL> if hinting else <EOL> cairo . Context ( cairo . PDFSurface ( None , <NUM_LIT:1> , <NUM_LIT:1> ) ) ) <EOL> self . layout = ffi . gc ( <EOL> pangocairo . pango_cairo_create_layout ( ffi . cast ( <EOL> '<STR_LIT>' , self . dummy_context . _pointer ) ) , <EOL> gobject . g_object_unref ) <EOL> self . font = font = ffi . gc ( <EOL> pango . pango_font_description_new ( ) , <EOL> pango . pango_font_description_free ) <EOL> assert not isinstance ( style . font_family , basestring ) , ( <EOL> '<STR_LIT>' ) <EOL> family_p , family = unicode_to_char_p ( '<STR_LIT:U+002C>' . join ( style . font_family ) ) <EOL> pango . pango_font_description_set_family ( font , family_p ) <EOL> pango . pango_font_description_set_variant ( <EOL> font , PANGO_VARIANT [ style . font_variant ] ) <EOL> pango . pango_font_description_set_style ( <EOL> font , PANGO_STYLE [ style . font_style ] ) <EOL> pango . pango_font_description_set_stretch ( <EOL> font , PANGO_STRETCH [ style . font_stretch ] ) <EOL> pango . pango_font_description_set_weight ( font , style . font_weight ) <EOL> pango . pango_font_description_set_absolute_size ( <EOL> font , units_from_double ( font_size ) ) <EOL> pango . pango_layout_set_font_description ( self . layout , font ) <EOL> def iter_lines ( self ) : <EOL> layout_iter = ffi . gc ( <EOL> pango . pango_layout_get_iter ( self . layout ) , <EOL> pango . pango_layout_iter_free ) <EOL> while <NUM_LIT:1> : <EOL> yield pango . pango_layout_iter_get_line_readonly ( layout_iter ) <EOL> if not pango . pango_layout_iter_next_line ( layout_iter ) : <EOL> return <EOL> def set_text ( self , text ) : <EOL> text , bytestring = unicode_to_char_p ( text ) <EOL> self . text = text <EOL> self . text_bytes = bytestring <EOL> pango . pango_layout_set_text ( self . layout , text , - <NUM_LIT:1> ) <EOL> def get_font_metrics ( self ) : <EOL> context = pango . pango_layout_get_context ( self . layout ) <EOL> return FontMetrics ( context , self . font ) <EOL> def set_wrap ( self , wrap_mode ) : <EOL> pango . pango_layout_set_wrap ( self . layout , wrap_mode ) <EOL> class FontMetrics ( object ) : <EOL> def __init__ ( self , context , font ) : <EOL> self . metrics = ffi . gc ( <EOL> pango . pango_context_get_metrics ( context , font , ffi . NULL ) , <EOL> pango . pango_font_metrics_unref ) <EOL> def __dir__ ( self ) : <EOL> return [ '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' ] <EOL> def __getattr__ ( self , key ) : <EOL> if key in dir ( self ) : <EOL> return units_to_double ( <EOL> getattr ( pango , '<STR_LIT>' + key ) ( self . metrics ) ) <EOL> def create_layout ( text , style , hinting , max_width ) : <EOL> """<STR_LIT>""" <EOL> layout = Layout ( hinting , style . font_size , style ) <EOL> layout . set_text ( text ) <EOL> if max_width is not None and max_width < <NUM_LIT:2> ** <NUM_LIT> : <EOL> pango . pango_layout_set_width ( <EOL> layout . layout , units_from_double ( max_width ) ) <EOL> word_spacing = style . word_spacing <EOL> letter_spacing = style . letter_spacing <EOL> if letter_spacing == '<STR_LIT>' : <EOL> letter_spacing = <NUM_LIT:0> <EOL> if text and ( word_spacing != <NUM_LIT:0> or letter_spacing != <NUM_LIT:0> ) : <EOL> letter_spacing = units_from_double ( letter_spacing ) <EOL> space_spacing = units_from_double ( word_spacing ) + letter_spacing <EOL> attr_list = pango . pango_attr_list_new ( ) <EOL> def add_attr ( start , end , spacing ) : <EOL> attr = pango . pango_attr_letter_spacing_new ( spacing ) <EOL> attr . start_index = start <EOL> attr . end_index = end <EOL> pango . pango_attr_list_insert ( attr_list , attr ) <EOL> text_bytes = layout . text_bytes <EOL> add_attr ( <NUM_LIT:0> , len ( text_bytes ) + <NUM_LIT:1> , letter_spacing ) <EOL> position = text_bytes . find ( b'<STR_LIT:U+0020>' ) <EOL> while position != - <NUM_LIT:1> : <EOL> add_attr ( position , position + <NUM_LIT:1> , space_spacing ) <EOL> position = text_bytes . find ( b'<STR_LIT:U+0020>' , position + <NUM_LIT:1> ) <EOL> pango . pango_layout_set_attributes ( layout . layout , attr_list ) <EOL> pango . pango_attr_list_unref ( attr_list ) <EOL> return layout <EOL> def split_first_line ( text , style , hinting , max_width , line_width ) : <EOL> """<STR_LIT>""" <EOL> layout = None <EOL> if max_width : <EOL> expected_length = int ( max_width / style . font_size * <NUM_LIT> ) <EOL> if expected_length < len ( text ) : <EOL> layout = create_layout ( <EOL> text [ : expected_length ] , style , hinting , max_width ) <EOL> lines = layout . iter_lines ( ) <EOL> first_line = next ( lines , None ) <EOL> second_line = next ( lines , None ) <EOL> if second_line is None : <EOL> layout = None <EOL> if layout is None : <EOL> layout = create_layout ( text , style , hinting , max_width ) <EOL> lines = layout . iter_lines ( ) <EOL> first_line = next ( lines , None ) <EOL> second_line = next ( lines , None ) <EOL> resume_at = None if second_line is None else second_line . start_index <EOL> if max_width is None : <EOL> return first_line_metrics ( first_line , text , layout , resume_at ) <EOL> first_line_width , _height = get_size ( first_line ) <EOL> if second_line is None and first_line_width <= max_width : <EOL> return first_line_metrics ( first_line , text , layout , resume_at ) <EOL> if first_line_width <= max_width : <EOL> second_line_index = second_line . start_index <EOL> first_line_text = utf8_slice ( text , slice ( second_line_index ) ) <EOL> second_line_text = utf8_slice ( text , slice ( second_line_index , None ) ) <EOL> else : <EOL> first_line_text = '<STR_LIT>' <EOL> second_line_text = text <EOL> next_word = second_line_text . split ( '<STR_LIT:U+0020>' , <NUM_LIT:1> ) [ <NUM_LIT:0> ] <EOL> if next_word : <EOL> new_first_line_text = first_line_text + next_word <EOL> layout . set_text ( new_first_line_text ) <EOL> lines = layout . iter_lines ( ) <EOL> first_line = next ( lines , None ) <EOL> second_line = next ( lines , None ) <EOL> first_line_width , _height = get_size ( first_line ) <EOL> if second_line is None and first_line_width <= max_width : <EOL> resume_at = len ( new_first_line_text . encode ( '<STR_LIT:utf-8>' ) ) + <NUM_LIT:1> <EOL> if resume_at == len ( text . encode ( '<STR_LIT:utf-8>' ) ) : <EOL> resume_at = None <EOL> return first_line_metrics ( first_line , text , layout , resume_at ) <EOL> elif first_line_text : <EOL> return first_line_metrics ( first_line , text , layout , resume_at ) <EOL> hyphens = style . hyphens <EOL> lang = style . lang and pyphen . language_fallback ( style . lang ) <EOL> total , left , right = style . hyphenate_limit_chars <EOL> hyphenated = False <EOL> if hyphens not in ( '<STR_LIT:none>' , '<STR_LIT>' ) and lang and len ( next_word ) >= total : <EOL> first_line_width , _height = get_size ( first_line ) <EOL> space = max_width - first_line_width <EOL> if style . hyphenate_limit_zone . unit == '<STR_LIT:%>' : <EOL> limit_zone = max_width * style . hyphenate_limit_zone . value / <NUM_LIT> <EOL> else : <EOL> limit_zone = style . hyphenate_limit_zone . value <EOL> if space > limit_zone or space < <NUM_LIT:0> : <EOL> dictionary_key = ( lang , left , right , total ) <EOL> dictionary = PYPHEN_DICTIONARY_CACHE . get ( dictionary_key ) <EOL> if dictionary is None : <EOL> dictionary = pyphen . Pyphen ( lang = lang , left = left , right = right ) <EOL> PYPHEN_DICTIONARY_CACHE [ dictionary_key ] = dictionary <EOL> for first_word_part , _ in dictionary . iterate ( next_word ) : <EOL> hyphenated_first_line_text = ( <EOL> first_line_text + first_word_part + <EOL> style . hyphenate_character ) <EOL> temp_layout = create_layout ( <EOL> hyphenated_first_line_text , style , hinting , max_width ) <EOL> temp_lines = temp_layout . iter_lines ( ) <EOL> temp_first_line = next ( temp_lines , None ) <EOL> temp_second_line = next ( temp_lines , None ) <EOL> if ( temp_second_line is None and space >= <NUM_LIT:0> ) or space < <NUM_LIT:0> : <EOL> hyphenated = True <EOL> resume_at = len ( <EOL> ( first_line_text + first_word_part ) . encode ( '<STR_LIT:utf8>' ) ) <EOL> layout = temp_layout <EOL> first_line = temp_first_line <EOL> second_line = temp_second_line <EOL> temp_first_line_width , _height = get_size ( temp_first_line ) <EOL> if temp_first_line_width <= max_width : <EOL> break <EOL> overflow_wrap = style . overflow_wrap <EOL> first_line_width , _height = get_size ( first_line ) <EOL> space = max_width - first_line_width <EOL> if overflow_wrap == '<STR_LIT>' and space < <NUM_LIT:0> : <EOL> hyphenated = False <EOL> temp_layout = create_layout ( text , style , hinting , max_width ) <EOL> temp_layout . set_wrap ( PANGO_WRAP_MODE [ '<STR_LIT>' ] ) <EOL> temp_lines = temp_layout . iter_lines ( ) <EOL> temp_first_line = next ( temp_lines , None ) <EOL> temp_second_line = next ( temp_lines , None ) <EOL> temp_second_line_index = ( <EOL> len ( text . encode ( '<STR_LIT:utf-8>' ) ) if temp_second_line is None <EOL> else temp_second_line . start_index ) <EOL> resume_at = temp_second_line_index <EOL> first_line_text = utf8_slice ( text , slice ( temp_second_line_index ) ) <EOL> layout = create_layout ( first_line_text , style , hinting , max_width ) <EOL> lines = layout . iter_lines ( ) <EOL> first_line = next ( lines , None ) <EOL> return first_line_metrics ( first_line , text , layout , resume_at , hyphenated ) <EOL> def line_widths ( text , style , enable_hinting , width ) : <EOL> """<STR_LIT>""" <EOL> layout = create_layout ( text , style , enable_hinting , width ) <EOL> for line in layout . iter_lines ( ) : <EOL> width , _height = get_size ( line ) <EOL> yield width <EOL> def show_first_line ( context , pango_layout , hinting ) : <EOL> """<STR_LIT>""" <EOL> context = ffi . cast ( '<STR_LIT>' , context . _pointer ) <EOL> if hinting : <EOL> pangocairo . pango_cairo_update_layout ( context , pango_layout . layout ) <EOL> pango . pango_layout_set_width ( pango_layout . layout , - <NUM_LIT:1> ) <EOL> pangocairo . pango_cairo_show_layout_line ( <EOL> context , next ( pango_layout . iter_lines ( ) ) ) </s>
