mirror of
https://github.com/Hopiu/bowser.git
synced 2026-03-16 19:10:24 +00:00
This commit introduces support for loading and rendering images in the Bowser web browser, enhancing the rendering engine to handle various image sources. Key changes include: - Updated README.md to reflect the new milestone status and added features for image support. - Added `ImageLayout` class to manage image layout and loading. - Implemented synchronous and asynchronous image loading in `src/network/images.py`, including caching mechanisms. - Expanded the DOM parsing capabilities in `DocumentLayout` to handle `<img>` tags and manage their layout directives. - Created a new `DrawImage` command in the rendering pipeline, which handles the drawing of both loaded images and placeholders for unloaded images. - Introduced a task queue for managing asynchronous image loads, ensuring UI remains responsive during image fetching. - Added unit tests for image loading, layout management, and the async task queue to ensure robust functionality and prevent regressions.
223 lines
7.1 KiB
Markdown
223 lines
7.1 KiB
Markdown
# Bowser — Educational Web Browser
|
|
|
|
A custom web browser built from scratch following the [browser.engineering](https://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
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# Debian/Ubuntu
|
|
sudo apt install libgtk-4-dev libadwaita-1-dev graphviz
|
|
```
|
|
|
|
### Testing
|
|
|
|
```bash
|
|
uv run pytest # Run all tests
|
|
uv run pytest -v # Verbose output
|
|
uv run pytest --cov=src # Coverage report
|
|
```
|
|
|
|
### Code Quality
|
|
|
|
```bash
|
|
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
|
|
|
|
- [x] **M0**: Project scaffold
|
|
- [x] **M1**: GTK window with Skia rendering
|
|
- [x] **M2**: HTML parsing and text layout
|
|
- [x] **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
|
|
|
|
```html
|
|
<!-- 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
|
|
|
|
- [Web Browser Engineering](https://browser.engineering/) — O'Reilly book
|
|
- [Let's Build a Browser Engine](https://limpet.net/mbrubeck/2014/08/08/toy-layout-engine-1.html) — Matt Brubeck
|
|
|
|
## License
|
|
|
|
MIT
|