Aperture UI
Engineer Notes

WebIDL to V8 Binding Generator

This system generates performant C++ V8 bindings from WebIDL interface definitions. It provides an offline code generation approach that creates static binding code, ensuring maximum performance and type safety.

WebIDL to V8 Binding Generator

This system generates performant C++ V8 bindings from WebIDL interface definitions. It provides an offline code generation approach that creates static binding code, ensuring maximum performance and type safety.

Location: Code/Tools/WebIDLGenerator/

This tool is part of the Aperture UI build system and generates V8 bindings for the APHTML module.

Overview

The WebIDL binding generator takes WebIDL interface definitions and generates:

  • C++ header files with binding declarations
  • C++ source files with V8 binding implementations
  • Static binding functions that can be called to register interfaces with V8 contexts

Features

  • Offline Generation: All bindings are generated at build time, no runtime parsing
  • High Performance: Direct V8 API usage with minimal overhead
  • Type Safety: Full C++ type mapping from WebIDL types
  • Comprehensive Support: Interfaces, enums, dictionaries, methods, attributes
  • Inheritance Support: Proper handling of interface inheritance
  • Error Handling: Robust error reporting and exception handling
  • CMake Integration: Seamless integration with build systems

Architecture

Components

  1. WebIDL Parser (WebIDLGenerator.cpp)
    • Parses WebIDL files using libclang's AST parsing capabilities
    • Converts IDL to C++-like structures for libclang parsing
    • Extracts interfaces, enums, dictionaries, methods, and attributes from AST
    • Handles inheritance and type relationships
    • Written in C++ for better integration and performance
  2. V8 Binding Generator
    • Generates C++ code for V8 bindings
    • Creates function templates and object templates
    • Implements property accessors and method callbacks
    • Uses Foundation library for robust string and file handling
  3. CMake Integration (libclang_util.cmake)
    • Provides build system integration
    • Handles file generation and dependency management
    • Supports multiple IDL files and output directories
    • Manages libclang dependencies

Generated Code Structure

generated/
├── WebIDLBindings.h          # Main binding header
├── WebIDLBindings.cpp        # Main binding implementation
├── Window.idl.h              # Window interface bindings
├── Window.idl.cpp
├── Navigator.idl.h           # Navigator interface bindings
├── Navigator.idl.cpp
└── ...                       # Additional interface bindings

Dependencies

LibClang

This generator requires libclang for robust WebIDL parsing. The system:

  1. Converts WebIDL to C++-like structures for libclang parsing
  2. Uses libclang's AST to extract interface definitions
  3. Provides accurate type information and inheritance relationships
  4. Handles complex WebIDL constructs with proper semantic analysis

Installation

Windows:

# Using vcpkg
vcpkg install llvm[clang]

# Or download from LLVM releases
# https://releases.llvm.org/

Linux:

# Ubuntu/Debian
sudo apt-get install libclang-dev

# CentOS/RHEL
sudo yum install clang-devel

# Or build from source
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build && cd build
cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release ../llvm
make -j$(nproc)
sudo make install

macOS:

# Using Homebrew
brew install llvm

# Or using MacPorts
sudo port install clang-10

Usage

1. Basic Setup

The WebIDL generator is automatically included when you build the Tools directory. The generator processes IDL files from Code/ApertureUISource/APHTML/dom/IDL/ and generates bindings in the build directory.

2. Building and Testing

# Build the generator
cmake --build build --target WebIDLGenerator --config Debug

# Build the test executables
cmake --build build --target WebIDLParserTest --config Debug
cmake --build build --target WebIDLIDLTest --config Debug

# Run the parser test
./build/WebIDLParserTest.exe

# Run the IDL files test (tests parsing of existing IDL files)
./build/WebIDLIDLTest.exe

3. Using the Provided Scripts

# Test the generator with existing IDL files
test_idl_generator.bat

# Generate bindings for all IDL files
generate_all_bindings.bat

4. Manual Generation

# Generate bindings for a single IDL file
./build/WebIDLGenerator.exe -input path/to/interface.idl -output path/to/output/dir

# Example
./build/WebIDLGenerator.exe -input ../../ApertureUISource/APHTML/dom/IDL/Window.idl -output ./generated

If you need to use the generator in a custom project, include the CMake utility:

include(${CMAKE_CURRENT_SOURCE_DIR}/BuildSystem/CMake/libclang_util.cmake)

5. Define IDL Files

List the WebIDL files you want to process:

set(IDL_FILES
    Window.idl
    Navigator.idl
    Console.idl
    Event.idl
    # ... more interfaces
)

6. Generate Bindings

Call the generation function:

generate_webidl_bindings(
    IDL_FILES ${IDL_FILES}
    IDL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dom/IDL
    OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated
)

7. Create Library

Build the generated bindings into a library:

add_library(WebIDLBindings STATIC
    ${GENERATED_SOURCES}
    ${GENERATED_HEADERS}
)

target_link_libraries(WebIDLBindings
    V8Engine
    Foundation
    ${V8_LIBRARIES}
)

8. Use in Code

#include "WebIDLBindings.h"
#include <v8.h>

// Initialize V8
v8::V8::InitializeICUDefaultLocation(".");
v8::V8::InitializeExternalStartupData(".");
v8::Platform* platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform);
v8::V8::Initialize();

// Create isolate and context
v8::Isolate* isolate = v8::Isolate::New(create_params);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);

v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> global = context->Global();

// Bind all WebIDL interfaces
if (!aperture::v8binding::WebIDLBindings::bindToContext(context, global))
{
    // Handle binding failure
}

// Now you can use JavaScript that accesses the bound interfaces
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, 
    "console.log('Window dimensions:', window.innerWidth, 'x', window.innerHeight);"
    "var div = document.createElement('div');"
    "div.textContent = 'Hello from bindings!';"
).ToLocalChecked();

v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

WebIDL Support

Supported Constructs

  • Interfaces: Full interface definitions with inheritance
  • Methods: Regular and static methods with parameters
  • Attributes: Read-only and read-write attributes
  • Enums: Enum definitions with string values
  • Dictionaries: Dictionary types with member attributes
  • Constants: Interface constants

Type Mapping

WebIDL TypeC++ TypeV8 Type
booleanboolv8::Boolean
byte, octet, short, unsigned shortintv8::Number
long, unsigned longintv8::Number
long long, unsigned long longint64_tv8::Number
floatfloatv8::Number
doubledoublev8::Number
DOMString, USVStringstd::stringv8::String
anyv8::Local<v8::Value>v8::Value
objectv8::Local<v8::Object>v8::Object
sequence<T>std::vector<T>v8::Array
Promisev8::Local<v8::Promise>v8::Promise
Interface typesstd::shared_ptr<InterfaceName>v8::Object

Performance Considerations

Optimizations

  1. Static Generation: All bindings are generated at build time
  2. Direct V8 API: Minimal abstraction layers
  3. Template Reuse: Efficient use of V8 function templates
  4. Memory Management: Proper V8 handle scoping
  5. Type Caching: Cached type conversions where possible

Best Practices

  1. Reuse Contexts: Create contexts once and reuse them
  2. Handle Scoping: Use proper V8 handle scoping
  3. Error Handling: Implement proper error handling in callbacks
  4. Memory Management: Be careful with V8 object lifecycle
  5. Batch Operations: Group related operations when possible

Error Handling

The generator provides comprehensive error handling:

// Check binding success
if (!WebIDLBindings::bindToContext(context, global))
{
    NS_LOG_ERROR("Failed to bind WebIDL interfaces");
    return false;
}

// Handle JavaScript errors
v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
if (try_catch.HasCaught())
{
    v8::String::Utf8Value error(isolate, try_catch.Exception());
    NS_LOG_ERROR("JavaScript error: {}", *error);
}

Advanced Usage

Custom Implementations

You can extend the generated bindings with custom implementations:

// Register custom method implementations
v8::Local<v8::FunctionTemplate> customMethod = v8::FunctionTemplate::New(isolate,
    [](const v8::FunctionCallbackInfo<v8::Value>& args) {
        // Custom implementation
        v8::Isolate* isolate = args.GetIsolate();
        // ... implementation
    }
);

// Add to existing interface
v8::Local<v8::ObjectTemplate> windowTemplate = /* get window template */;
windowTemplate->Set(
    v8::String::NewFromUtf8(isolate, "customMethod").ToLocalChecked(),
    customMethod
);

Selective Binding

Bind only specific interfaces:

// Bind individual interfaces
WebIDLBindings::bindInterface(context, global, "Window");
WebIDLBindings::bindInterface(context, global, "Console");

Custom Type Conversions

Extend type conversion for custom types:

// Custom type conversion function
v8::Local<v8::Value> convertCustomType(const CustomType& value, v8::Isolate* isolate)
{
    v8::Local<v8::Object> obj = v8::Object::New(isolate);
    obj->Set(isolate->GetCurrentContext(),
        v8::String::NewFromUtf8(isolate, "property").ToLocalChecked(),
        v8::String::NewFromUtf8(isolate, value.property.c_str()).ToLocalChecked()
    ).Check();
    return obj;
}

Integration with Existing Systems

DOM Integration

The generated bindings integrate seamlessly with existing DOM implementations:

// Your existing DOM classes
class DOMWindow : public std::enable_shared_from_this<DOMWindow>
{
public:
    static void bindToV8(v8::Local<v8::Context> context, v8::Local<v8::Object> global);
    // ... implementation
};

// In the binding implementation
void DOMWindow::bindToV8(v8::Local<v8::Context> context, v8::Local<v8::Object> global)
{
    // Use the generated binding code
    WebIDLBindings::bindWindow(context, global);
}

Event System Integration

// Integrate with existing event system
class EventDispatcher
{
public:
    void dispatchEvent(const std::string& type, v8::Local<v8::Object> target);
};

// In event binding callbacks
v8::Local<v8::FunctionTemplate> addEventListener = v8::FunctionTemplate::New(isolate,
    [](const v8::FunctionCallbackInfo<v8::Value>& args) {
        // Integrate with your event system
        EventDispatcher::getInstance().addEventListener(/* ... */);
    }
);

Build System Integration

CMake Configuration

# Include the utility
include(${CMAKE_CURRENT_SOURCE_DIR}/BuildSystem/CMake/libclang_util.cmake)

# Set up IDL processing
set(IDL_FILES ${YOUR_IDL_FILES})
generate_webidl_bindings(
    IDL_FILES ${IDL_FILES}
    IDL_DIR ${IDL_DIR}
    OUTPUT_DIR ${GENERATED_DIR}
)

# Create library
add_library(YourBindings STATIC ${GENERATED_SOURCES})
target_link_libraries(YourBindings V8Engine Foundation)

Dependencies

The system requires:

  • V8 engine (version 8.0 or later)
  • Foundation library
  • C++17 compiler
  • libclang (for parsing support)

Troubleshooting

Common Issues

  1. Binding Failures: Check that IDL files are valid and accessible
  2. Type Errors: Verify WebIDL type definitions match C++ implementations
  3. Memory Leaks: Ensure proper V8 handle scoping
  4. Performance Issues: Check for unnecessary object creation in callbacks

Debugging

Enable debug logging:

// Enable V8 debug output
v8::V8::SetFlagsFromString("--trace-gc --trace-gc-verbose");

// Enable Foundation logging
NS_LOG_SET_LEVEL(NS_LOG_LEVEL_DEBUG);

Examples

See Example.cpp for a complete working example demonstrating:

  • Basic V8 initialization
  • WebIDL binding registration
  • JavaScript execution
  • DOM manipulation
  • Event handling
  • Custom function registration
  • Error handling

Contributing

When adding new WebIDL interfaces:

  1. Add the IDL file to the IDL_FILES list in CMakeLists.txt
  2. Ensure the IDL syntax is correct
  3. Test the generated bindings
  4. Update documentation if needed

License

This code is part of Aperture UI and is subject to the same licensing terms as the rest of the project.

Copyright © 2026