ó
    �®žj  ã                  óæ   • S r SSKJr  SSKrSSKJr  SSKJr  SSKJ	r	  SSK
Jr  \(       a  SSKrSSKJrJr  \R$                  " \5      r " S	 S
\	5      r\SS j5       rSS jrSS jr    SS jrg)aä  Extract a PDF's outline (bookmarks / table-of-contents).

The outline, when present, is the most authoritative heading-hierarchy signal in a PDF. Two
extractors are provided so each backend uses its own native capability:

* :func:`extract_outline_from_pdfium` -- for the pypdfium2 backend. Returns the richest data:
  title, depth, target page and vertical position.
* :func:`extract_outline_from_docling_parse` -- for the docling-parse backends, using their native
  ``get_table_of_contents()`` (no pypdfium2 dependency). The native outline carries titles and
  hierarchy only, so page number and position are left unset.

``pypdfium2`` is imported lazily, inside the functions that use it, never at module level:
``datamodel.document`` imports this module for the ``_PdfOutlineItem`` model, which places it on
the ``docling.service_client`` import chain. That chain must stay importable on any docling-slim
install that does not enable the PDF pipeline (and therefore ships no ``pypdfium2``).
é    )ÚannotationsN)Úcache)ÚTYPE_CHECKING)Ú	BaseModel)Úpypdfium2_lock)ÚPdfDocumentÚPdfTableOfContentsc                  óJ   • \ rS rSr% SrS\S'   S\S'   SrS\S	'   SrS
\S'   Srg)Ú_PdfOutlineItemé)   ak  A single PDF bookmark / table-of-contents entry (internal).

Internal data-passing structure between a PDF backend's ``get_document_outline()`` and the
heading-hierarchy stage; not part of the public datamodel or the serialized output. The list
is kept flat and in document order; each entry carries its own ``level`` so no tree structure
is needed for matching.
ÚstrÚtitleÚintÚlevelNz
int | NoneÚpage_nozfloat | NoneÚy_top© )	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__r   r   Ú__static_attributes__r   ó    ÚV/home/mande/repo/quber/.venv/lib/python3.13/site-packages/docling/utils/pdf_outline.pyr   r   )   s'   ‡ ñð ƒJàƒJà€GˆZÓà€Eˆ<Ör   r   c                 ór   • SSK Jn   U R                  SU R                  SU R                  SU R
                  S0$ )al  Destination view modes whose coordinates carry a usable vertical (top) position.

Coordinates are in PDF space (bottom-left origin). Modes not listed (FIT, FITV, FITB,
FITBV, unknown) provide no top.

Returns:
    A mapping of each supported ``PDFDEST_VIEW_*`` mode to the index of the vertical (top)
    coordinate within that mode's position tuple:

    * ``PDFDEST_VIEW_XYZ`` -> ``1`` (position is ``[x, y, zoom]``)
    * ``PDFDEST_VIEW_FITH`` -> ``0`` (position is ``[y]``)
    * ``PDFDEST_VIEW_FITBH`` -> ``0`` (position is ``[y]``)
    * ``PDFDEST_VIEW_FITR`` -> ``3`` (position is ``[left, bottom, right, top]``)
r   Né   é   )Úpypdfium2.rawÚrawÚPDFDEST_VIEW_XYZÚPDFDEST_VIEW_FITHÚPDFDEST_VIEW_FITBHÚPDFDEST_VIEW_FITR)Úpdfium_cs    r   Ú_view_top_indexr'   ;   s?   € õ" %ð 	×!Ñ! 1Ø×"Ñ" AØ×#Ñ# QØ×"Ñ" Að	ð r   c                ó®   • U R                  5       nU R                  5       u  p#[        5       R                  U5      nUb  U[	        U5      :  a  X4   OSnX4$ )z�Return ``(0-based page index, vertical top in PDF bottom-left coords)`` for a dest.

Either element may be ``None`` when the destination does not encode it.
N)Ú	get_indexÚget_viewr'   ÚgetÚlen)ÚdestÚ
page_indexÚmodeÚposÚidxÚy_pdfs         r   Ú_dest_top_pdfr3   V   sP   € ð
 —‘Ó!€JØ—‘“�I€DÜ
Ó
×
Ñ
 Ó
%€CØ™¨C´#°c³(«NˆCŠHÀ€EØÐÐr   c                ó¤  • SSK Jn  / n0 n[            [        U R	                  5       5      nU HÂ  nUR                  5       =(       d    SR                  5       nU(       d  M3  SnSn	 UR                  5       n
U
bJ  [        U
5      u  p¼Ub:  US-   nUb2  X³;  a&  X   nUR                  5       X;'   UR                  5         X;   U-
  n	UR                  [        U[        UR                   5      X‰S95        MÄ     SSS5        U$ ! U a+  n[
        R                  SU5        / s SnAsSSS5        $ SnAff = f! U a    Sn
 NÆf = f! , (       d  f       U$ = f)a  Extract the outline as a flat, document-ordered list of :class:`_PdfOutlineItem`.

Vertical positions are converted to top-left origin (matching ``DocItem`` provenance) using
the target page height. Returns an empty list when the document has no outline or it cannot
be read.
r   )ÚPdfiumErrorzCould not read PDF outline: %sNÚ r   )r   r   r   r   )Úpypdfium2._helpers.miscr5   r   ÚlistÚget_tocÚ_logÚdebugÚ	get_titleÚstripÚget_destr3   Ú
get_heightÚcloseÚappendr   r   r   )Úpdocr5   ÚitemsÚpage_heightsÚtocÚexcÚbmr   r   r   r-   r.   r2   Úpages                 r   Úextract_outline_from_pdfiumrI   b   sN  € õ 4à#%€EØ%'€Læ	ð	Ü�t—|‘|“~Ó&ˆCó
 ˆBØ—\‘\“^×) r×0Ñ0Ó2ˆEÞÙà"&ˆGØ"&ˆEðØ—{‘{“}�ð ÑÜ$1°$Ó$7Ñ!�
ØÑ)Ø(¨1™n�GØÑ(Ø%Ó9Ø#'Ñ#3˜DØ7;·±Ó7H˜LÑ4Ø ŸJ™JœLØ ,Ñ 8¸5Ñ @˜à�L‰LÜØ¤s¨2¯8©8£}¸gñöñ- ÷ 
ðF €LøðA ó 	Ü�J‰JÐ7¸Ô=ØŒI÷ 
‰ûð	ûð ó Ø’ðú÷! 
ŒðF €Lús^   ‘E “C>¬9E Á&D2Á6A>E Ã>D/ÄD*ÄD/ÄE Ä*D/Ä/E Ä2D=Ä:E Ä<D=Ä=E Å 
Ec                óþ  ^• U R                  5       nUc  / $ / n[        UR                  =(       d    / 5       Vs/ s H  o3S4PM     nnU(       a©  UR                  5       u  nmUR                  =(       d    UR
                  =(       d    SR                  5       nU(       a  UR                  [        UTS95        UR                  U4S j[        UR                  =(       d    / 5       5       5        U(       a  M©  U$ s  snf )aŠ  Flatten docling-parse's native table-of-contents into ordered ``_PdfOutlineItem``\ s.

Walks the ``PdfTableOfContents`` tree returned by ``PdfDocument.get_table_of_contents()``,
depth-first, assigning each node a 0-based ``level`` from its depth (top-level entries at
level 0, matching the pypdfium2 extractor). The native outline exposes only the title and
the tree structure -- no target page or vertical position -- so ``page_no`` and ``y_top``
are left ``None`` and the heading matcher falls back to title-only matching.

``get_table_of_contents()`` returns ``None`` for PDFs without an embedded outline, in which
case an empty list is returned.
r   r6   )r   r   c              3  ó0   >#   • U  H  oTS -   4v •  M     g7f)r   Nr   )Ú.0Úchildr   s     €r   Ú	<genexpr>Ú5extract_outline_from_docling_parse.<locals>.<genexpr>µ   s   øé € ÐSÒ5R¨E˜U Q™YÕ'Ò5Rùs   ƒ)
Úget_table_of_contentsÚreversedÚchildrenÚpopÚtextÚorigr=   rA   r   Úextend)Údp_docrE   rC   rM   ÚstackÚnoder   r   s          @r   Ú"extract_outline_from_docling_parserZ   •   sÎ   ø€ ð ×
&Ñ
&Ó
(€CØ
�{Øˆ	à#%€Eô !)¨¯©×);¸Ô <ó3Ú <�u�‹
Ñ <ð 
ð 3ö Ø—i‘i“k‰ˆˆeØ—‘×-˜dŸi™i×-¨2×4Ñ4Ó6ˆÞØ�L‰Lœ¨u¸EÑBÔCØ�‰ÔS´X¸d¿m¹m×>QÈrÔ5RÓSÔS÷ ˆ%ð €Lùò3s   ¹C:)Úreturnzdict[int, int])r-   zpdfium.PdfDestr[   ztuple[int | None, float | None])rB   zpdfium.PdfDocumentr[   úlist[_PdfOutlineItem])rW   ÚDoclingParsePdfDocumentr[   r\   )r   Ú
__future__r   ÚloggingÚ	functoolsr   Útypingr   Úpydanticr   Údocling.utils.locksr   Ú	pypdfium2ÚpdfiumÚdocling_parse.pdf_parserr   r]   r	   Ú	getLoggerr   r:   r   r'   r3   rI   rZ   r   r   r   Ú<module>rh      s{   ðñõ" #ã Ý Ý  å å .æÛ÷ð
 ×Ò˜Ó"€ô�iô ð$ óó ðô4	ô0ðf"Ø#ð"àõ"r   