No description
Find a file
Benedikt Willi 8c2d360515 This commit introduces several enhancements to the browser rendering engine. Key changes include the ability to handle link clicks, improved link detection, and enhanced color parsing for proper rendering of styled links. The following modifications are included:
- **Link Detection and Navigation**: Added functionality to detect if a mouse click falls within a link area. If a link is clicked, the browser now navigates to the corresponding URL while logging the action. This also includes handling relative URLs based on the current page context.

- **Line Layout Enhancements**: The `LayoutLine` class now includes optional attributes for color and href, allowing links to maintain their designated colors in the rendered output.

- **Color Parsing**: Implemented a new `_parse_color` method in the `RenderPipeline` class to convert various color formats (hex and named colors) to Skia-compatible values. This ensures that default link colors are correctly applied and that extremely light colors are rendered as black for visibility.

- **Rendering Links**: During the rendering process, links in the text layout are now rendered with their specified colors, and an underline is drawn under links to indicate interactivity.

- **Document Layout Updates**: The document parsing system has been updated to extract link information correctly while preserving text hierarchy.

- **Tests**: A comprehensive suite of tests has been added, including tests for link parsing, layout characteristics, styling application, and default color handling for links.
2026-01-13 13:06:20 +01:00
.github Refactor test files to remove unnecessary imports and improve readability 2026-01-12 10:22:34 +01:00
assets Implement image loading and rendering support in Bowser browser 2026-01-12 17:36:14 +01:00
src This commit introduces several enhancements to the browser rendering engine. Key changes include the ability to handle link clicks, improved link detection, and enhanced color parsing for proper rendering of styled links. The following modifications are included: 2026-01-13 13:06:20 +01:00
tests This commit introduces several enhancements to the browser rendering engine. Key changes include the ability to handle link clicks, improved link detection, and enhanced color parsing for proper rendering of styled links. The following modifications are included: 2026-01-13 13:06:20 +01:00
.gitignore Enhance layout and rendering features with new document and block layout implementations 2026-01-11 23:34:27 +01:00
main.py Refactor test files to remove unnecessary imports and improve readability 2026-01-12 10:22:34 +01:00
pyproject.toml Refactor test files to remove unnecessary imports and improve readability 2026-01-12 10:22:34 +01:00
README.md Implement image loading and rendering support in Bowser browser 2026-01-12 17:36:14 +01:00
uv.lock Refactor test files to remove unnecessary imports and improve readability 2026-01-12 10:22:34 +01:00

Bowser — Educational Web Browser

A custom web browser built from scratch following the browser.engineering curriculum. Features a clean architecture with Skia-based rendering, GTK 4/Adwaita UI, and proper separation of concerns.

Status: Milestone 3 - Basic HTML rendering with text layout and image support

Features

  • Adwaita Tab Bar - Modern GNOME-style tab management
  • Skia Rendering - Hardware-accelerated 2D graphics
  • Text Layout - Word wrapping, character-level selection
  • Image Support - Load and render images from HTTP, data URLs, and local files
  • DOM Parsing - HTML parsing with proper tree structure
  • Debug Mode - Visual layout debugging with FPS counter
  • DOM Visualization - Generate visual graphs of page structure

Quick Start

# Install dependencies and run
uv sync
uv run bowser

# Browse a website
uv run bowser example.com

# Enable debug mode (shows FPS, layout boxes)
uv run bowser example.com --debug

Keyboard Shortcuts

Shortcut Action
Ctrl+T New tab
Ctrl+W Close tab
Ctrl+L Focus address bar
Ctrl+Shift+D Generate DOM visualization
Ctrl+Shift+O Toggle debug mode

Architecture

bowser/
├── src/
│   ├── browser/           # Browser UI (chrome.py, tab.py)
│   │   ├── browser.py     # Application orchestration
│   │   ├── chrome.py      # GTK/Adwaita window, tab bar, address bar
│   │   └── tab.py         # Tab and frame management
│   │
│   ├── parser/            # Document parsing
│   │   ├── html.py        # HTML → DOM tree (Element, Text nodes)
│   │   └── css.py         # CSS parsing (stub)
│   │
│   ├── layout/            # Layout calculation
│   │   ├── document.py    # DocumentLayout - full page layout
│   │   ├── block.py       # BlockLayout, LineLayout - block elements
│   │   ├── inline.py      # TextLayout, InlineLayout - text runs
│   │   └── embed.py       # ImageLayout - embedded content
│   │
│   ├── render/            # Painting & rendering
│   │   ├── pipeline.py    # RenderPipeline - coordinates layout/paint
│   │   ├── fonts.py       # FontCache - Skia font management
│   │   ├── paint.py       # DisplayList, DrawText, DrawRect, DrawImage
│   │   └── composite.py   # Layer compositing
│   │
│   ├── network/           # Networking
│   │   ├── http.py        # HTTP client with redirects
│   │   ├── url.py         # URL parsing and normalization
│   │   ├── cookies.py     # Cookie management
│   │   ├── images.py      # Image loading and caching
│   │   └── tasks.py       # Async task queue for background loading
│   │
│   ├── debug/             # Development tools
│   │   └── dom_graph.py   # DOM tree visualization
│   │
│   └── templates.py       # Page templates (start page, errors)
│
├── tests/                 # Test suite
└── main.py                # Entry point

Design Principles

Separation of Concerns:

  • parser/ - Pure DOM data structures (Element, Text)
  • layout/ - Position and size calculations (x, y, width, height)
  • render/ - Drawing commands and font management
  • browser/ - UI only (tabs, address bar, event handling)

Key Classes:

Class Package Responsibility
Element, Text parser DOM tree nodes
DocumentLayout layout Page layout with line positioning
LayoutLine, LayoutBlock layout Positioned text with bounding boxes
ImageLayout, LayoutImage layout Image sizing and positioning
RenderPipeline render Coordinates layout → paint
DrawImage render Image rendering command
FontCache render Skia font caching
ImageCache network Image loading and caching
Chrome browser GTK window, delegates to RenderPipeline

Development

Prerequisites

  • Python 3.11+
  • GTK 4 (libgtk-4-dev libgtk-4-1)
  • libadwaita (libadwaita-1-dev)
  • Graphviz (optional, for DOM visualization)
# Debian/Ubuntu
sudo apt install libgtk-4-dev libadwaita-1-dev graphviz

Testing

uv run pytest              # Run all tests
uv run pytest -v           # Verbose output
uv run pytest --cov=src    # Coverage report

Code Quality

uv run black src tests     # Format code
uv run ruff check src      # Lint
uv run mypy src            # Type check

Debug Mode

Enable with --debug flag or press Ctrl+Shift+O at runtime.

Shows:

  • FPS counter with frame timing breakdown
  • Layout boxes colored by element type:
    • Red: Block elements (<div>, <p>)
    • Blue: Inline elements (<span>, <a>)
    • Green: List items (<li>)

Milestones

  • M0: Project scaffold
  • M1: GTK window with Skia rendering
  • M2: HTML parsing and text layout
  • M3: Image loading and rendering
  • M4: CSS parsing and styling
  • M5: Clickable links and navigation
  • M6: Form input and submission
  • M7: JavaScript execution
  • M8: Event handling

Image Support

Bowser supports loading and rendering images from multiple sources:

Supported Sources

  • HTTP/HTTPS URLs: <img src="https://example.com/image.png">
  • Data URLs: <img src="data:image/png;base64,...">
  • Local files: <img src="file:///path/to/image.png">

Features

  • Async loading: Images load in background threads, keeping UI responsive
  • Smart sizing: Respects width/height attributes, maintains aspect ratios
  • Caching: Thread-safe global image cache prevents redundant loads
  • Alt text placeholders: Shows placeholder with alt text when images fail
  • Format support: PNG, JPEG, GIF, WebP, and more (via Skia)
  • Viewport culling: Only renders visible images for performance
  • Progressive display: Page shows immediately, images appear as they load

Example

<!-- Basic image -->
<img src="photo.jpg">

<!-- Sized image with aspect ratio -->
<img src="photo.jpg" width="300">

<!-- With alt text for accessibility -->
<img src="photo.jpg" alt="A beautiful sunset">

<!-- Data URL (embedded image) -->
<img src="data:image/png;base64,iVBORw0KG...">

Architecture

HTML <img> tag
    ↓
ImageLayout.load(async=True)
    ↓
TaskQueue (background thread pool)
    ↓
load_image() → HTTP/file/data URL
    ↓                    ↓
ImageCache          GLib.idle_add
(thread-safe)            ↓
                   on_complete callback
                         ↓
                   ImageLayout.image = loaded
                         ↓
                   RenderPipeline._request_redraw()
                         ↓
                   DrawImage.execute() → Canvas

References

License

MIT