-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5f0553d
commit 499b07f
Showing
14 changed files
with
537 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,71 +1,106 @@ | ||
# Software Architecture. | ||
|
||
**WIP: Consider this document as a draft!!!** | ||
|
||
This details design document is about [gdcef] | ||
(https://github.com/Lecrapouille/gdcef) implementing a [Chromium Embedded | ||
Framework](https://bitbucket.org/chromiumembedded/cef/wiki/Home) (CEF) native | ||
module for the [Godot editor](https://godotengine.org/) (gdCef). | ||
|
||
Inside the `gdcef` folder, two main classes deriving from `godot::Node` have | ||
been created to wrap the CEF C++ API to be usable from Godot scripts. Derived | ||
from Godot Nodes, it allows instances of these classes to be attached inside to | ||
the scene-graph as depicted by the following picture. | ||
|
||
![CEFnode](pics/cef.png) | ||
|
||
See this | ||
[document](https://docs.godotengine.org/en/stable/classes/class_node.html) | ||
concerning what a Godot Node is. | ||
|
||
## Classes Diagram | ||
|
||
The following picture depicts the class diagram: | ||
|
||
![classdiag](architecture/classes.png) | ||
|
||
- `GDCef` implemented in [gdcef/src/gdcef.cpp](gdcef.[ch]pp). Its goal is to | ||
wrap up the initialization phase of CEF, its settings, and the loopback of | ||
messages of CEF subprocesses. This class allows creating `GDBrowserView` | ||
that are attached as child nodes inside the scene-graph. | ||
|
||
- `GDBrowserView` implemented in [gdcef/src/gdbrowser.cpp](gdbrowser.[ch]pp). | ||
Its goal is to wrap a browser view allowing to display the web document, to | ||
interact with the user (mouse, keyboard), to load pages, ... | ||
|
||
The [gdcef/src/gdlibrary.cpp](gdcef/src/gdlibrary.cpp) allows Godot to | ||
register the two classes. See this document for more information: | ||
https://docs.godotengine.org/en/stable/development/cpp/custom_modules_in_cpp.html | ||
|
||
## CEF Secondary process | ||
|
||
A [secondary CEF | ||
process](https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-separate-sub-process-executable) | ||
is needed when CEF (here, our class `GDCef`) cannot directly access the | ||
`main(int argc, char* argv[])` function of the application. This is mandatory for | ||
its initialization. | ||
<!--- | ||
This is, unfortunately, the case since CEF is created as a node | ||
scene-graph but CEF does not come natively inside the Godot engine and | ||
accessing the Godot engine `main` function. | ||
--> | ||
This is, unfortunately, the case since CEF is created as a Node scene-graph | ||
but CEF and its access to Godot Engine's `main` function do not exist | ||
in Godot's source code. | ||
|
||
When starting, CEF will fork the application several times into processes | ||
and the forked processes become specialized processes | ||
|
||
You have to know that CEF modifies the content of your `argv` and this may mess | ||
up your application if it also parses the command line (you can back it up, | ||
meaning using a `std::vector` to back up `argv` and after CEF init to restore | ||
values in `argv` back). What is "two separated processes" exactly? Just an extra | ||
fork: the main process forks itself and calls the secondary process, which can | ||
fully access it is own main(int argc, char* argv[]). The main constraint is the | ||
path of the secondary process shall be canonic (and this is a pain to get the | ||
real path). | ||
|
||
<!--- | ||
## Diagram sequence | ||
--> | ||
# Software Architecture | ||
|
||
This document details the software architecture of [gdcef](https://github.com/Lecrapouille/gdcef), a native module for the [Godot engine](https://godotengine.org/) that implements the [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef/wiki/Home) (CEF). | ||
|
||
## Overview | ||
|
||
The gdcef module consists of two main components: | ||
|
||
1. A main process that handles CEF initialization and browser management | ||
2. A render process that handles web page rendering and JavaScript execution | ||
|
||
## Core Components | ||
|
||
### Main Process Classes | ||
|
||
Two main classes are exposed to Godot as Nodes: | ||
|
||
#### GDCef Class | ||
|
||
Implemented in `gdcef/src/gdcef.hpp`, this class serves as the entry point: | ||
|
||
- **GDCef**: The entry point class that: | ||
- Initializes CEF and manages its lifecycle | ||
- Handles CEF settings and configuration | ||
- Creates and manages browser instances | ||
- Routes messages between CEF subprocesses | ||
|
||
- **GDBrowserView**: Represents a browser instance that: | ||
- Manages web page display and rendering | ||
- Handles user interactions (mouse, keyboard) | ||
- Controls page navigation and JavaScript execution | ||
- Manages audio streaming | ||
- Handles file downloads | ||
|
||
These classes are derived from `godot::Node`, allowing them to be integrated into Godot's scene tree: | ||
|
||
![CEF node integration](pics/cef.png) | ||
|
||
### Render Process | ||
|
||
The render process is implemented in a separate executable and handles: | ||
|
||
- Web page rendering | ||
- JavaScript execution | ||
- V8 context management | ||
- Communication with the main process | ||
|
||
## Communication Flow | ||
|
||
### Initialization Sequence | ||
|
||
![Init Sequence](architecture/sequence_init.png) | ||
|
||
1. GDScript initializes GDCef with configuration | ||
2. CEF initializes and forks required processes | ||
3. The render process starts and initializes its components | ||
4. Browser instances can then be created | ||
|
||
### Rendering Sequence | ||
|
||
![Paint Sequence](architecture/sequence_paint.png) | ||
|
||
1. The render process renders web content | ||
2. Content is painted to an off-screen buffer | ||
3. The buffer is converted to a Godot texture | ||
4. The texture is displayed in the Godot scene | ||
|
||
### Download Sequence | ||
|
||
![Download Sequence](architecture/sequence_download.png) | ||
|
||
1. Download is initiated from browser | ||
2. CEF handles the download process | ||
3. Progress updates are sent to Godot | ||
4. Download completion is signaled | ||
|
||
## Class Relationships | ||
|
||
The following diagram shows the relationships between the main components: | ||
|
||
![Class Diagram](architecture/class_diagram.png) | ||
|
||
### Key Relationships | ||
|
||
- GDCef creates and manages GDBrowserView instances | ||
- GDBrowserView communicates with CEF browser instances | ||
- The render process communicates with both GDCef and browser instances | ||
- All CEF-related classes implement appropriate CEF interfaces | ||
|
||
## Implementation Details | ||
|
||
- The module uses CEF's windowless rendering mode for seamless integration with Godot | ||
- Audio is routed through Godot's audio system | ||
- JavaScript integration allows bidirectional communication between Godot and web content | ||
- File downloads are managed through CEF's download handler interface | ||
- Mouse and keyboard events are translated from Godot to CEF format | ||
|
||
## Technical Constraints | ||
|
||
- CEF requires a separate render process executable | ||
- The render process path must be canonical | ||
- CEF modifies command line arguments during initialization | ||
- Memory management must account for both Godot's reference counting and CEF's reference counting | ||
|
||
For API documentation and usage examples, please refer to [API.md](API.md). | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
@startuml | ||
|
||
skinparam class { | ||
BackgroundColor White | ||
ArrowColor Black | ||
BorderColor Black | ||
} | ||
|
||
package "CEF Framework" #LightBlue { | ||
namespace cef { | ||
interface CefApp { | ||
{abstract} | ||
+GetRenderProcessHandler() | ||
} | ||
|
||
interface CefClient { | ||
{abstract} | ||
+GetRenderHandler() | ||
+GetLifeSpanHandler() | ||
+GetLoadHandler() | ||
} | ||
|
||
interface CefRenderProcessHandler { | ||
{abstract} | ||
+OnContextCreated() | ||
} | ||
|
||
interface CefV8Handler { | ||
{abstract} | ||
+Execute() | ||
} | ||
|
||
interface CefRenderHandler { | ||
{abstract} | ||
+GetViewRect() | ||
+OnPaint() | ||
} | ||
} | ||
} | ||
|
||
package "Godot Framework" #LightGreen { | ||
namespace godot { | ||
class Object { | ||
{abstract} | ||
} | ||
class Node { | ||
{abstract} | ||
} | ||
class TextureRect { | ||
} | ||
|
||
Node --|> Object | ||
TextureRect --|> Node | ||
} | ||
} | ||
|
||
package "GDCEF Core" #LightYellow { | ||
class GDCef { | ||
-m_impl: GDCef::Impl* | ||
-m_cef_settings: CefSettings | ||
+initialize(config: Dictionary): bool | ||
+shutdown(): void | ||
+create_browser(): GDBrowserView* | ||
+isAlive(): bool | ||
+get_error(): String | ||
+get_full_version(): String | ||
+get_version_part(entry: int): int | ||
+register_method(godot_object: Object, browser: GDBrowserView, method_name: String): void | ||
} | ||
|
||
class "GDCef::Impl" as GDCefImpl { | ||
-m_gdcef: GDCef& | ||
+OnBeforeCommandLineProcessing() | ||
+OnAfterCreated() | ||
+DoClose() | ||
+OnBeforeClose() | ||
+closeAllBrowsers() | ||
} | ||
|
||
GDCef --|> godot::Node | ||
GDCef *-- GDCefImpl | ||
GDCefImpl ..|> cef::CefApp | ||
} | ||
|
||
package "GDCEF Browser" #LightPink { | ||
class GDBrowserView { | ||
-m_impl: GDBrowserView::Impl* | ||
-m_texture: Ref<ImageTexture> | ||
+init(url: String): int | ||
+load_url(url: String): void | ||
+resize(size: Vector2): void | ||
+execute_javascript(code: String): void | ||
+close(): void | ||
+id(): int | ||
+get_error(): String | ||
+is_valid(): bool | ||
+set_texture(texture: ImageTexture): void | ||
+get_texture(): ImageTexture | ||
+set_zoom_level(level: float): void | ||
+get_title(): String | ||
+get_url(): String | ||
+load_data_uri(html: String, mime_type: String): void | ||
+download_file(url: String): void | ||
+allow_downloads(allow: bool): void | ||
+set_download_folder(path: String): void | ||
+is_loaded(): bool | ||
+reload(): bool | ||
+stop_loading(): void | ||
+copy(): void | ||
+paste(): void | ||
+undo(): void | ||
+redo(): void | ||
+request_html_content(): void | ||
+has_previous_page(): bool | ||
+has_next_page(): bool | ||
+previous_page(): void | ||
+next_page(): void | ||
+set_viewport(x: float, y: float, w: float, h: float): bool | ||
+set_key_pressed(key: int): void | ||
+set_mouse_moved(x: int, y: int): void | ||
+set_mouse_left_click(x: int, y: int): void | ||
+set_mouse_right_click(x: int, y: int): void | ||
+set_mouse_middle_click(x: int, y: int): void | ||
+set_mouse_left_down(x: int, y: int): void | ||
+set_mouse_left_up(x: int, y: int): void | ||
+set_mouse_right_down(x: int, y: int): void | ||
+set_mouse_right_up(x: int, y: int): void | ||
+set_mouse_middle_down(x: int, y: int): void | ||
+set_mouse_middle_up(x: int, y: int): void | ||
+set_mouse_wheel_vertical(delta: int): void | ||
+set_mouse_wheel_horizontal(delta: int): void | ||
+set_muted(mute: bool): bool | ||
+is_muted(): bool | ||
+set_audio_stream(audio: AudioStreamGeneratorPlayback): void | ||
+get_audio_stream(): AudioStreamGeneratorPlayback | ||
+get_pixel_color(x: int, y: int): Color | ||
} | ||
|
||
class "GDBrowserView::Impl" as GDBrowserViewImpl { | ||
-m_browser: CefRefPtr<CefBrowser> | ||
-m_texture_rect: TextureRect* | ||
+GetViewRect() | ||
+OnPaint() | ||
+OnLoadEnd() | ||
+OnLoadError() | ||
+OnBeforePopup() | ||
+OnBeforeDownload() | ||
+OnDownloadUpdated() | ||
+OnProcessMessageReceived() | ||
+OnAudioStreamStarted() | ||
+OnAudioStreamPacket() | ||
} | ||
|
||
GDBrowserView --|> godot::Node | ||
GDBrowserView *-- GDBrowserViewImpl | ||
GDBrowserView o-- godot::TextureRect | ||
GDBrowserViewImpl ..|> cef::CefClient | ||
GDBrowserViewImpl ..|> cef::CefRenderHandler | ||
} | ||
|
||
package "Render Process" #LightGray { | ||
class RenderProcess { | ||
-m_handler: CefRefPtr<GodotMethodHandler> | ||
+GetRenderProcessHandler() | ||
+OnContextCreated() | ||
} | ||
|
||
class GodotMethodHandler { | ||
-m_browser: CefRefPtr<CefBrowser> | ||
+Execute() | ||
} | ||
|
||
RenderProcess ..|> cef::CefApp | ||
RenderProcess ..|> cef::CefRenderProcessHandler | ||
RenderProcess *-- GodotMethodHandler | ||
GodotMethodHandler ..|> cef::CefV8Handler | ||
|
||
' Interactions avec GDCEF Core | ||
RenderProcess ..> GDCef : "Communique avec" | ||
GodotMethodHandler ..> GDCef : "Envoie des messages à" | ||
} | ||
|
||
note top of GDCef | ||
Main entry point that initializes CEF | ||
and manages browser instances | ||
end note | ||
|
||
note top of GDBrowserView | ||
Represents a browser instance | ||
with its own texture | ||
end note | ||
|
||
note top of RenderProcess | ||
Manages the render process | ||
and JavaScript bindings | ||
end note | ||
|
||
@enduml |
Oops, something went wrong.