CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-rinohtype

A comprehensive Python document processing library that renders structured documents to PDF with advanced typography and customizable styling

Pending
Overview
Eval results
Files

layout-engine.mddocs/

Layout Engine

Advanced layout system managing container-based document layout, automatic text flow, pagination, and precise element positioning. The layout engine handles the complex task of transforming flowable content into positioned elements on pages while respecting layout constraints and style requirements.

Capabilities

Container System

Core container classes that define rectangular areas for content placement and provide the foundation for document layout.

class Container:
    """
    Rectangular rendering area for flowable content.
    
    Parameters:
    - name: str, container identifier
    - parent: Container, parent container (None for root)
    - left: Dimension, left edge position
    - top: Dimension, top edge position  
    - width: Dimension, container width
    - height: Dimension, container height  
    - clip: bool, whether to clip overflow content
    """
    def __init__(self, name, parent, left=None, top=None, width=None, height=None, clip=False): ...
    
    # Properties
    @property
    def width(self): ...  # Container width
    @property  
    def height(self): ...  # Container height
    @property
    def cursor(self): ...  # Current vertical position
    @property
    def remaining_height(self): ...  # Available height remaining
    
    # Layout methods
    def render(self, flowable, last_descender=None): ...  # Render flowable in container
    def place(self, item, width, height, baseline=None): ...  # Place item at cursor
    def advance(self, height): ...  # Move cursor down by height
    def advance2(self, advance_type): ...  # Advance cursor by type
    
    # Positioning
    def float_space(self, float_spec): ...  # Get space for floated elements
    def mark_page_nonempty(self): ...  # Mark page as containing content

class FlowablesContainer(Container):
    """Container specialized for flowing flowable content."""
    
    def render_flowable(self, flowable, last_descender, state, first_line_only=False): ...

class ChainedContainer(Container):
    """Container that can overflow to next container in chain."""
    
    @property
    def next(self): ...  # Next container in chain
    def create_next_container(self): ...  # Create overflow container

Container Types

Specialized container types for different layout scenarios and content flow patterns.

class DownExpandingContainer(FlowablesContainer):
    """
    Container that expands downward as content is added.
    
    Automatically grows in height to accommodate content while
    maintaining position and width constraints.
    """
    def __init__(self, name, parent, left=None, top=None, width=None, clip=False): ...

class InlineDownExpandingContainer(DownExpandingContainer):
    """Inline version of down-expanding container for inline content."""

class UpExpandingContainer(FlowablesContainer):
    """
    Container that expands upward from a fixed bottom position.
    
    Used for footnotes and other bottom-anchored content.
    """
    def __init__(self, name, parent, left=None, bottom=None, width=None, clip=False): ...

class UpDownExpandingContainer(FlowablesContainer):
    """
    Container that can expand both upward and downward.
    
    Maintains a center position while growing in both directions
    as content is added.
    """
    def __init__(self, name, parent, left=None, center=None, width=None, clip=False): ...

class VirtualContainer(Container):
    """
    Non-placing container used for measurements and calculations.
    
    Allows content to be measured and processed without actually
    placing it in the document layout.
    """
    def __init__(self, container): ...
    
    def place(self, item, width, height, baseline=None): ...  # No-op placement

class MaybeContainer(Container):
    """Container that may or may not be used based on conditions."""
    
    def __init__(self, name, parent, condition, *args, **kwargs): ...

Specialized Containers

Task-specific containers for handling special layout requirements like footnotes and floating elements.

class FootnoteContainer(UpExpandingContainer):
    """
    Specialized container for footnote content at page bottom.
    
    Manages footnote placement, numbering, and separation from
    main content while handling overflow across pages.
    
    Parameters:
    - name: str, container identifier
    - parent: Container, parent page container
    - left: Dimension, left edge position
    - bottom: Dimension, bottom edge position
    - width: Dimension, container width
    """
    def __init__(self, name, parent, left, bottom, width): ...
    
    def add_footnote(self, note): ...  # Add footnote to container
    def prepare_footnote(self, note, note_marker): ...  # Prepare footnote layout

Container Chains

Chain system for connecting containers to enable content overflow across pages and columns.

class Chain:
    """
    Series of connected containers for content overflow.
    
    Manages the flow of content from one container to the next
    when content doesn't fit in the current container.
    
    Parameters:
    - name: str, chain identifier
    """
    def __init__(self, name): ...
    
    def append(self, container): ...  # Add container to chain
    def prepend(self, container): ...  # Add container at beginning
    def remove(self, container): ...  # Remove container from chain
    
    @property
    def first_container(self): ...  # First container in chain
    @property 
    def last_container(self): ...  # Last container in chain

class ChainedContainer(Container):
    """Container that participates in a chain for overflow handling."""
    
    @property
    def chain(self): ...  # Chain this container belongs to
    @property
    def previous(self): ...  # Previous container in chain
    @property
    def next(self): ...  # Next container in chain

Layout Exceptions

Exception types for handling layout-specific error conditions and control flow.

class ContainerOverflow(Exception):
    """
    Raised when content doesn't fit in available container space.
    
    Parameters:
    - flowable: Flowable that caused overflow
    - container: Container where overflow occurred
    """
    def __init__(self, flowable, container): ...

class EndOfContainer(Exception):
    """
    Raised when reaching end of container during layout.
    
    Signals that no more content can be placed in current container
    and overflow handling should be triggered.
    """

class PageBreakException(Exception): 
    """
    Raised to force a page break at current position.
    
    Used by page break elements and manual break requests to
    interrupt normal flow and move to next page.
    """

Flowable Layout Interface

Core interface that all flowable content must implement for participation in the layout system.

class Flowable(Styled):
    """
    Base class for content that can flow through containers.
    
    All document content elements inherit from Flowable and implement
    the flow/render protocol for layout system integration.
    """
    
    def flow(self, container, last_descender, state=None):
        """
        Flow content into container with layout state management.
        
        Parameters:
        - container: Container to flow content into
        - last_descender: Dimension, previous content's descender
        - state: layout state from previous flow attempt
        
        Returns:
        - (width, height, baseline, state): layout result tuple
        """
        ...
    
    def render(self, container, descender, state=None, first_line_only=False):
        """
        Render content at current container position.
        
        Parameters:
        - container: Container to render content in
        - descender: Dimension, descender from previous content
        - state: layout state for partial rendering
        - first_line_only: bool, render only first line if True
        
        Returns:
        - layout state for continuation if needed
        """
        ...
    
    def initial_state(self, container):
        """
        Create initial layout state for this flowable.
        
        Parameters:
        - container: Container where flowable will be placed
        
        Returns:
        - initial state object for flow/render operations
        """
        ...

Usage Examples

Basic Container Usage

from rinohtype.layout import Container, DownExpandingContainer
from rinohtype.dimension import PT, MM
from rinohtype.paragraph import Paragraph

# Create parent container (page area)
page_container = Container(
    name='page',
    parent=None,
    left=25*MM,
    top=25*MM, 
    width=160*MM,
    height=247*MM  # A4 with margins
)

# Create content container that expands downward
content_container = DownExpandingContainer(
    name='content',
    parent=page_container,
    left=0*PT,
    top=0*PT,
    width=160*MM
)

# Flow content into container
paragraph = Paragraph("This is sample content that will flow into the container.")
result = paragraph.flow(content_container, last_descender=0*PT)

if result:
    width, height, baseline, state = result
    paragraph.render(content_container, descender=0*PT, state=state)
    content_container.advance(height)

Container Chain for Multi-Page Layout

from rinohtype.layout import Chain, ChainedContainer

# Create container chain for multi-column or multi-page layout
main_chain = Chain('main_content')

# Create first page container
page1_container = ChainedContainer(
    name='page1',
    parent=None,
    left=25*MM,
    top=25*MM,
    width=160*MM, 
    height=220*MM
)
main_chain.append(page1_container)

# Create second page container (linked automatically)
page2_container = ChainedContainer(
    name='page2', 
    parent=None,
    left=25*MM,
    top=25*MM,
    width=160*MM,
    height=220*MM  
)
main_chain.append(page2_container)

# Flow long content across pages
long_content = [
    Paragraph("First paragraph..."),
    Paragraph("Second paragraph..."),
    # ... more content
]

current_container = main_chain.first_container
for paragraph in long_content:
    try:
        result = paragraph.flow(current_container, last_descender=0*PT)
        if result:
            paragraph.render(current_container, descender=0*PT)
    except ContainerOverflow:
        # Move to next container in chain
        current_container = current_container.next
        if current_container:
            result = paragraph.flow(current_container, last_descender=0*PT)
            paragraph.render(current_container, descender=0*PT)

Footnote Container Usage

from rinohtype.layout import FootnoteContainer
from rinohtype.reference import Note

# Create footnote container at bottom of page
footnote_container = FootnoteContainer(
    name='footnotes',
    parent=page_container,
    left=0*PT,
    bottom=0*PT,
    width=160*MM
)

# Add footnotes to container
footnote1 = Note([Paragraph("This is a footnote.")])
footnote2 = Note([Paragraph("Another footnote with more content.")])

footnote_container.add_footnote(footnote1)
footnote_container.add_footnote(footnote2)

Virtual Container for Measurements

from rinohtype.layout import VirtualContainer

# Create virtual container for measuring content
virtual = VirtualContainer(content_container)

# Measure content without placing it
test_paragraph = Paragraph("Test content for measurement")
result = test_paragraph.flow(virtual, last_descender=0*PT)

if result:
    width, height, baseline, state = result
    print(f"Content would be {width} wide and {height} tall")
    
    # Now place it for real if it fits
    if height <= content_container.remaining_height:
        test_paragraph.render(content_container, descender=0*PT, state=state)

Error Handling

from rinohtype.layout import ContainerOverflow, EndOfContainer, PageBreakException

def flow_content_safely(flowable, container):
    """Flow content with proper error handling."""
    try:
        result = flowable.flow(container, last_descender=0*PT)
        if result:
            flowable.render(container, descender=0*PT)
            return True
    except ContainerOverflow as e:
        print(f"Content overflow in {e.container.name}")
        # Handle overflow - move to next page/container
        return False
    except EndOfContainer:
        print("Reached end of container")
        return False
    except PageBreakException:
        print("Page break requested")
        # Handle page break
        return False

Custom Container Implementation

from rinohtype.layout import FlowablesContainer

class CustomContainer(FlowablesContainer):
    """Custom container with special layout behavior."""
    
    def __init__(self, name, parent, **kwargs):
        super().__init__(name, parent, **kwargs)
        self.special_mode = True
    
    def render_flowable(self, flowable, last_descender, state, first_line_only=False):
        """Custom rendering logic."""
        if self.special_mode:
            # Apply custom layout rules
            pass
        
        return super().render_flowable(flowable, last_descender, state, first_line_only)
    
    def advance(self, height):
        """Custom cursor advancement."""
        if self.special_mode:
            # Custom spacing rules
            height = height * 1.1
        
        super().advance(height)

Install with Tessl CLI

npx tessl i tessl/pypi-rinohtype

docs

dimensions.md

document-structure.md

graphics-images.md

index.md

layout-engine.md

references.md

styling-system.md

template-system.md

typography-text.md

tile.json