
    j5j/                        d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlmZ  ej                  e      Z G d d	      Zy)
zMulti-font management for PDF rendering.

Provides automatic font selection for multilingual documents based on
language hints and glyph coverage analysis.
    )annotationsN)Path)FontManager)BuiltinFontProviderChainedFontProviderFontProvider)SystemFontProviderc                     e Zd ZdZi ddddddddddddd	d
dd
dd
dd
dd
dd
dd
ddddddddi ddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d1d3d3d4d4d5d6d6d7d7d8d8d9Zg d:Z	 dFd;d<	 	 	 dGd=ZedHd>       Z	 	 	 	 	 	 	 	 dId?Z		 	 	 	 	 	 dJd@Z
dKdAZdLdBZdMdCZdNdDZdHdEZy;)OMultiFontManagera  Manages multiple fonts with automatic selection and fallback.

    This class orchestrates multiple FontManager instances to provide
    word-level font selection for multilingual documents. It uses a hybrid
    approach combining language hints from hOCR with glyph coverage analysis.

    Font selection strategy:
    1. Try language-preferred font (if language hint available)
    2. Try fallback fonts in order by glyph coverage
    3. Fall back to Occulta.ttf (glyphless fallback)
    araNotoSansArabic-RegularperfasurdpuskurhinNotoSansDevanagari-RegularsanmarnepkokbhomaichiNotoSansCJK-Regularzhochi_simchi_trajpnkorthaNotoSansThai-RegularhebNotoSansHebrew-RegularyidbenNotoSansBengali-RegularasmtamNotoSansTamil-RegulargujNotoSansGujarati-RegulartelNotoSansTelugu-RegularkanNotoSansKannada-RegularmalNotoSansMalayalam-RegularmyaNotoSansMyanmar-RegularkhmNotoSansKhmer-RegularlaoNotoSansLao-RegularkatNotoSansGeorgian-RegulargeoNotoSansArmenian-RegularNotoSansEthiopic-RegularNotoSansSinhala-RegularNotoSansGurmukhi-RegularNotoSansOriya-RegularNotoSansTibetan-Regular)hyearmamhtirsinpanpnboriorybodtib)zNotoSans-Regularr   r   r   r#   r%   r(   r+   r-   r/   r1   r3   r5   r7   r9   r;   r=   r>   r?   r@   rA   rB   N)font_providerc                   ||| _         n#t        t        |      t               g      | _         i | _        t               | _        y)a  Initialize multi-font manager.

        Args:
            font_dir: Directory containing font files. If font_provider is
                      not specified, this is passed to BuiltinFontProvider.
            font_provider: Provider for loading fonts. If None, uses a
                           ChainedFontProvider that tries builtin fonts first,
                           then searches system fonts.
        N)rN   r   r   r	   _selection_cacheset_warned_scripts)selffont_dirrN   s      V/var/www/html/qr/venv/lib/python3.12/site-packages/ocrmypdf/font/multi_font_manager.py__init__zMultiFontManager.__init__   sJ     $!.D "5'1&("D DF),    c                "    | j                         S )z.Get all loaded fonts (backward compatibility).)get_all_fonts)rS   s    rU   fontszMultiFontManager.fonts   s     !!##rW   c                    | j                   j                  |      }|y| j                  ||      r|| j                  |<   |S y)a0  Try to use a font for the given word.

        Args:
            font_name: Name of font to try
            word_text: Text content to check
            cache_key: Cache key for storing successful result

        Returns:
            FontManager if font exists and has all glyphs, None otherwise
        N)rN   get_font_has_all_glyphsrP   )rS   	font_name	word_text	cache_keyfonts        rU   	_try_fontzMultiFontManager._try_font   sJ     !!**95<i0/8D!!),KrW   c                   ||f}|| j                   v r.| j                   |   }| j                  j                  |      }|r|S t               }|rE|| j                  v r7| j                  |   }|j                  |       | j                  |||      x}r|S | j                  D ]   }	|	|v r| j                  |	||      x}s|c S  | j                  ||       d| j                   |<   | j                  j                         S )a  Select appropriate font for a word.

        Uses a hybrid approach:
        1. Language-based selection (if language hint available)
        2. Ordered fallback through available fonts by glyph coverage
        3. Final fallback to Occulta.ttf (glyphless)

        Args:
            word_text: The text content of the word
            line_language: Language code from hOCR (e.g., 'ara', 'eng')

        Returns:
            FontManager instance to use for rendering this word
        Occulta)
rP   rN   r\   rQ   LANGUAGE_FONT_MAPaddrb   FALLBACK_FONTS_warn_missing_fontget_fallback_font)
rS   r_   line_languager`   cached_namera   tried_fonts	preferredresultr^   s
             rU   select_font_for_wordz%MultiFontManager.select_font_for_word   s   " .	---//	:K%%..{;D # ]d.D.DD..}=IOOI&	9iHHvH ,, 	IK'	9iHHvH		 		=9+4i(!!3355rW   c                "   |r|nd}|| j                   v ryt        d |D              sy| j                   j                  |       |r5|| j                  v r'| j                  |   }t        j                  d||       yt        j                  d       y)zyWarn user about missing font for non-Latin text.

        Only warns once per language/script to avoid log spam.
        unknownNc              3  8   K   | ]  }t        |      d kD    yw)   N)ord).0cs     rU   	<genexpr>z6MultiFontManager._warn_missing_font.<locals>.<genexpr>   s     3A3q6C<3s   zkNo font found with glyphs for '%s' text. Install %s for better rendering. See https://fonts.google.com/notozsNo font found with glyphs for some text. Install Noto fonts for better rendering. See https://fonts.google.com/noto)rR   anyrf   re   logwarning)rS   r_   rj   warn_keyr^   s        rU   rh   z#MultiFontManager._warn_missing_font   s     %2=y t+++ 333  *]d.D.DD..}=IKK4  KK4rW   c                    |sy|j                         }|D ]'  }t        |      }|j                  |      }||dk(  s' y y)a  Check if a font has glyphs for all characters in text.

        Args:
            font: FontManager instance to check
            text: Text to verify coverage for

        Returns:
            True if font has real glyphs for all characters (not .notdef)
        Tr   F)get_hb_fontrt   get_nominal_glyph)rS   ra   texthb_fontchar	codepointglyph_ids          rU   r]   z MultiFontManager._has_all_glyphs  sT     ""$ 	DD	I00;H8q=		 rW   c                <    | j                   j                  |      duS )zCheck if a named font is available.

        Args:
            font_name: Name of font to check

        Returns:
            True if font is available
        N)rN   r\   )rS   r^   s     rU   has_fontzMultiFontManager.has_font)  s      !!**95TAArW   c                b    | j                   j                  |      }|y| j                  ||      S )a  Check if a named font has glyphs for all characters in text.

        Args:
            font_name: Name of font to check
            text: Text to verify coverage for

        Returns:
            True if font has real glyphs for all characters (not .notdef)
        F)rN   r\   r]   )rS   r^   r   ra   s       rU   has_all_glyphszMultiFontManager.has_all_glyphs4  s5     !!**95<##D$//rW   c                    i }| j                   j                         D ]%  }| j                   j                  |      }|!|||<   ' |S )z{Get all loaded font managers.

        Returns:
            Dictionary mapping font names to FontManager instances
        )rN   get_available_fontsr\   )rS   rn   namera   s       rU   rY   zMultiFontManager.get_all_fontsC  sS     &&::< 	$D%%..t4D#t	$ rW   )N)rT   zPath | NonerN   zFontProvider | None)returnzdict[str, FontManager])r^   strr_   r   r`   ztuple[str, str | None]r   zFontManager | None)r_   r   rj   
str | Noner   r   )r_   r   rj   r   r   None)ra   r   r   r   r   bool)r^   r   r   r   )r^   r   r   r   r   r   )__name__
__module____qualname____doc__re   rg   rV   propertyrZ   rb   ro   rh   r]   r   r   rY    rW   rU   r   r      s   
C'C 	'C 	'	C
 	'C 	'C 	'C 	+C 	+C 	+C 	+C 	+C 	+C 	+C" 	$#C$ 	$%C& 	('C( 	()C* 	$+C, 	$-C0 	%1C4 	'5C6 	'7C: 	(;C< 	(=C@ 	&ACD 	)ECH 	'ICL 	(MCP 	*QCT 	(UCX 	&YC\ 	$]C` 	)aCb 	)cCf *)))())&&((ECNN6 !%/ .2	// +	/> $ $),9O	*,6,6-7,6	,6\ D.	B0rW   r   )r   
__future__r   loggingpathlibr   ocrmypdf.font.font_managerr   ocrmypdf.font.font_providerr   r   r   "ocrmypdf.font.system_font_providerr	   	getLoggerr   ry   r   r   rW   rU   <module>r      sF    #   2 
 Bg!t trW   