mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-18 19:43:24 +03:00
- Reimplement previews using nested UISceneNodes with isolated styles and resources. - Preserve live XML/CSS editing, unsaved buffer previews, external file watching, and project resource loading. - Use UIApplication for initialization, font resolution, and offscreen rendering support. - Enable Breeze by default, add a menu toggle, and replace --use-app-theme with --disable-app-theme. - Automatically preserve declared project viewport dimensions, with an optional override to use the preview split size. - Support embedded HTML documents inside WebView XML elements. - Fix fading window shadows and shutdown with visible modal dialogs. - Update documentation and add regression coverage.
1513 lines
37 KiB
Markdown
1513 lines
37 KiB
Markdown
# HTML Compatibility Layer
|
|
|
|
eepp includes an HTML/CSS compatibility layer for rendering document-like content inside the UI
|
|
system.
|
|
|
|
This layer is used primarily by:
|
|
|
|
- `UIWebView`;
|
|
- `UIMarkdownView`;
|
|
- HTML-derived widgets such as `UIRichText`, `UITextSpan`, HTML tables, forms, images, and inputs.
|
|
|
|
It is intentionally distinct from normal eepp application UI authoring.
|
|
|
|
For ordinary application UI, use native eepp layouts such as `vbox`, `hbox`,
|
|
`UIRelativeLayout`, `UIGridLayout`, `UIFlowLayout`, `UISplitter`, and `UITabWidget`.
|
|
See [`ui_authoring.md`](ui_authoring.md),
|
|
[`ui_layout_reference.md`](ui_layout_reference.md), and
|
|
[`ui_css_for_applications.md`](ui_css_for_applications.md).
|
|
|
|
This document describes the **HTML compatibility model**, the browser-style layout concepts it
|
|
implements, and the important places where it differs from a full browser engine.
|
|
|
|
---
|
|
|
|
## 1. The most important boundary
|
|
|
|
eepp has two related but different layout worlds.
|
|
|
|
### Native application UI
|
|
|
|
Normal eepp application interfaces use:
|
|
|
|
```text
|
|
UILinearLayout / vbox / hbox
|
|
UIRelativeLayout
|
|
UIGridLayout
|
|
UIFlowLayout
|
|
UISplitter
|
|
UITabWidget
|
|
UIScrollView
|
|
layout-width
|
|
layout-height
|
|
layout-weight
|
|
layout-gravity
|
|
```
|
|
|
|
CSS can configure those widgets, but CSS does not replace their native layout algorithms.
|
|
|
|
### HTML compatibility UI
|
|
|
|
HTML-derived widgets can instead participate in browser-style formatting contexts:
|
|
|
|
```text
|
|
block
|
|
inline
|
|
inline-block
|
|
list-item
|
|
|
|
flex
|
|
inline-flex
|
|
|
|
grid
|
|
inline-grid
|
|
|
|
table
|
|
|
|
float / clear
|
|
absolute / fixed / sticky positioning
|
|
```
|
|
|
|
The same CSS parser and property system are shared by both worlds, but the **layout semantics depend
|
|
on the widget type and formatting context**.
|
|
|
|
Do not use browser layout properties merely because the stylesheet parser accepts them.
|
|
|
|
---
|
|
|
|
## 2. `UIWebView` is the full document host
|
|
|
|
`UIWebView` is the main host for HTML documents.
|
|
|
|
It is implemented as a `UIScrollView` containing an embedded `UISceneNode` dedicated to the loaded
|
|
document.
|
|
|
|
Conceptually:
|
|
|
|
```text
|
|
UIWebView
|
|
scroll viewport
|
|
embedded UISceneNode
|
|
document container
|
|
html
|
|
head
|
|
body
|
|
```
|
|
|
|
The embedded scene gives the document its own:
|
|
|
|
- widget tree;
|
|
- stylesheet state;
|
|
- document URI;
|
|
- resource loading context;
|
|
- font-face registrations;
|
|
- navigation handling;
|
|
- text-selection context.
|
|
|
|
Use:
|
|
|
|
```cpp
|
|
auto* webView = UIWebView::New();
|
|
webView->loadURI( URI( "file:///path/document.html" ) );
|
|
```
|
|
|
|
or an HTTP/HTTPS URI.
|
|
|
|
Native XML layouts can also embed a document directly:
|
|
|
|
```xml
|
|
<webview layout_width="match_parent" layout_height="180dp">
|
|
<html>
|
|
<head><style>p { color: #4085a9; }</style></head>
|
|
<body><p>Embedded HTML document</p></body>
|
|
</html>
|
|
</webview>
|
|
```
|
|
|
|
The containing layout must be well-formed XML. The WebView consumes its `<html>` child and loads it
|
|
through the normal HTML document pipeline in its isolated scene. Document CSS does not affect the
|
|
host or sibling WebViews. Relative stylesheets, images, and links use the containing scene's URI;
|
|
set that URI to the layout's file URI when loading layouts from memory. Embedded loading emits the
|
|
normal navigation and title events without adding the containing layout to URL history.
|
|
|
|
`UIWebView` supports navigation history through:
|
|
|
|
```cpp
|
|
goHistoryBack();
|
|
goHistoryForward();
|
|
refresh();
|
|
reload();
|
|
canGoBack();
|
|
canGoForward();
|
|
```
|
|
|
|
It also exposes navigation events for started, completed, and failed loads.
|
|
|
|
---
|
|
|
|
## 3. `UIMarkdownView` uses the HTML compatibility layer too
|
|
|
|
`UIMarkdownView` converts Markdown to XHTML and then loads the resulting body children as eepp HTML
|
|
widgets.
|
|
|
|
Its pipeline is approximately:
|
|
|
|
```text
|
|
Markdown
|
|
-> Markdown::toXHTML()
|
|
-> HTMLFormatter::HTMLBodyToXML()
|
|
-> eepp HTML widgets
|
|
```
|
|
|
|
Unlike `UIWebView`, `UIMarkdownView` shares its enclosing scene and does not create a dedicated
|
|
embedded scene. It can follow local Markdown links without changing the shared scene's URI.
|
|
|
|
It is a native vertical layout hosting HTML-derived content and loads the **basic HTML default
|
|
styles** needed for Markdown rendering.
|
|
|
|
Use `UIMarkdownView` for rendered Markdown content, not as a general browser replacement.
|
|
|
|
---
|
|
|
|
## 4. HTML is parsed before eepp widgets are created
|
|
|
|
`UIWebView` does not feed arbitrary HTML directly into the normal XML layout parser.
|
|
|
|
HTML is first parsed with Gumbo, then serialized into strict XML through
|
|
`Tools::HTMLFormatter`.
|
|
|
|
This stage handles browser-style HTML parsing details such as:
|
|
|
|
- malformed/non-XML HTML syntax;
|
|
- omitted closing syntax where HTML permits it;
|
|
- HTML void elements;
|
|
- boolean attributes;
|
|
- normalized tag names.
|
|
|
|
The resulting strict XML is then loaded through eepp's widget creation system.
|
|
|
|
This architecture is important:
|
|
|
|
```text
|
|
HTML source
|
|
-> Gumbo HTML tree
|
|
-> strict XML representation
|
|
-> UIWidgetCreator
|
|
-> eepp widget tree
|
|
```
|
|
|
|
The final rendered document is therefore still made of eepp widgets.
|
|
|
|
---
|
|
|
|
## 5. Only registered HTML elements are materialized
|
|
|
|
HTML compatibility is not based on a generic DOM element class that accepts every possible tag.
|
|
|
|
HTML tags are mapped through `UIWidgetCreator`.
|
|
|
|
Currently registered HTML elements include the major supported groups:
|
|
|
|
```text
|
|
document:
|
|
html
|
|
head
|
|
body
|
|
|
|
text and inline:
|
|
a
|
|
label
|
|
span
|
|
em
|
|
b
|
|
strong
|
|
small
|
|
i
|
|
cite
|
|
kbd
|
|
sub
|
|
sup
|
|
time
|
|
u
|
|
ins
|
|
s
|
|
strike
|
|
del
|
|
font
|
|
code
|
|
abbr
|
|
tt
|
|
mark
|
|
|
|
blocks:
|
|
div
|
|
p
|
|
blockquote
|
|
h1 ... h6
|
|
br
|
|
hr
|
|
pre
|
|
|
|
lists:
|
|
ul
|
|
ol
|
|
dl
|
|
dt
|
|
dd
|
|
li
|
|
|
|
semantic containers:
|
|
header
|
|
article
|
|
figure
|
|
figcaption
|
|
footer
|
|
main
|
|
section
|
|
nav
|
|
aside
|
|
center
|
|
|
|
interactive/details:
|
|
details
|
|
summary
|
|
|
|
media/replaced content:
|
|
picture
|
|
img
|
|
svg
|
|
|
|
forms:
|
|
form
|
|
input
|
|
textarea
|
|
button
|
|
|
|
tables:
|
|
table
|
|
thead
|
|
tbody
|
|
tfoot
|
|
tr
|
|
th
|
|
td
|
|
```
|
|
|
|
The exact set is defined in:
|
|
|
|
```text
|
|
src/eepp/ui/uiwidgetcreator.cpp
|
|
```
|
|
|
|
An unregistered tag does not automatically become a transparent generic HTML container.
|
|
|
|
Applications can register additional widget creators if they need custom tags.
|
|
|
|
---
|
|
|
|
## 6. This is not a JavaScript browser runtime
|
|
|
|
`<script>` nodes are ignored by the UI layout loader.
|
|
|
|
The HTML compatibility layer should therefore be understood as:
|
|
|
|
```text
|
|
HTML parsing
|
|
CSS styling
|
|
document layout
|
|
native interaction for supported elements
|
|
navigation/resource loading
|
|
```
|
|
|
|
not as:
|
|
|
|
```text
|
|
HTML + DOM + JavaScript browser engine
|
|
```
|
|
|
|
There is no browser JavaScript environment or general DOM scripting model implied by `UIWebView`.
|
|
|
|
If application logic is required, implement it through eepp/C++ behavior.
|
|
|
|
---
|
|
|
|
## 7. Default HTML styles
|
|
|
|
eepp provides built-in HTML default styles.
|
|
|
|
The basic defaults cover conventional document presentation for elements such as:
|
|
|
|
```text
|
|
body
|
|
h1 ... h6
|
|
p
|
|
pre
|
|
blockquote
|
|
hr
|
|
ul / ol / dl
|
|
b / strong
|
|
i / em
|
|
small
|
|
u / ins
|
|
s / strike / del
|
|
code / kbd
|
|
sub / sup
|
|
mark
|
|
a
|
|
summary
|
|
```
|
|
|
|
`UIWebView` also loads document-oriented defaults for controls and document colors, including
|
|
inputs, textareas, buttons, checkboxes, and radio buttons.
|
|
|
|
These defaults are inserted with lower selector specificity so author styles can override them.
|
|
|
|
`UIMarkdownView` loads the basic HTML defaults rather than the complete standalone-document defaults.
|
|
|
|
The source of the defaults is:
|
|
|
|
```text
|
|
src/eepp/ui/uiwidgetcreator.cpp
|
|
```
|
|
|
|
---
|
|
|
|
## 8. HTML attributes and native XML attributes have different cascade behavior
|
|
|
|
This is an important distinction.
|
|
|
|
For **normal native eepp widgets**, XML attributes are treated as inline-style properties with
|
|
inline specificity.
|
|
|
|
For widgets marked as HTML elements, ordinary HTML attributes are loaded with low specificity so
|
|
CSS can override them in the expected HTML-like way.
|
|
|
|
For example:
|
|
|
|
```html
|
|
<img width="200" class="preview">
|
|
```
|
|
|
|
can still be overridden by author CSS:
|
|
|
|
```css
|
|
.preview {
|
|
width: 100px;
|
|
}
|
|
```
|
|
|
|
The explicit HTML `style` attribute remains inline style:
|
|
|
|
```html
|
|
<img style="width: 200px">
|
|
```
|
|
|
|
and therefore has inline specificity.
|
|
|
|
This distinction exists specifically so HTML presentation attributes do not behave like native eepp
|
|
XML configuration.
|
|
|
|
---
|
|
|
|
## 9. Attribute selectors are supported
|
|
|
|
The selector engine supports attribute selectors.
|
|
|
|
For HTML widgets, `data-*` attributes are stored as HTML data properties and can participate in
|
|
attribute matching.
|
|
|
|
Examples:
|
|
|
|
```css
|
|
input[type="text"] {
|
|
...
|
|
}
|
|
|
|
input[type="password"] {
|
|
...
|
|
}
|
|
|
|
[data-state="warning"] {
|
|
...
|
|
}
|
|
```
|
|
|
|
Supported attribute operators include:
|
|
|
|
```text
|
|
[attr]
|
|
[attr=value]
|
|
[attr~=value]
|
|
[attr|=value]
|
|
[attr^=value]
|
|
[attr$=value]
|
|
[attr*=value]
|
|
```
|
|
|
|
For native widgets, attribute selectors operate through properties exposed by the widget property
|
|
system.
|
|
|
|
For HTML widgets, `data-*` attributes are additionally available directly.
|
|
|
|
---
|
|
|
|
## 10. Block and inline formatting
|
|
|
|
The HTML layer implements separate formatting behavior for:
|
|
|
|
```css
|
|
display: block;
|
|
display: inline;
|
|
display: inline-block;
|
|
display: list-item;
|
|
display: none;
|
|
```
|
|
|
|
Block and inline content is laid out through the HTML layouter system rather than native
|
|
`UILinearLayout`.
|
|
|
|
Inline text and inline widgets are integrated into `RichText` line construction.
|
|
|
|
This includes:
|
|
|
|
- text runs;
|
|
- line wrapping;
|
|
- inline boxes;
|
|
- atomic inline boxes;
|
|
- inline replaced elements;
|
|
- baselines;
|
|
- line-height;
|
|
- vertical alignment;
|
|
- inline background/text painting.
|
|
|
|
Block elements participate in vertical document flow and intrinsic sizing.
|
|
|
|
`display: none` removes the element from layout and hit testing.
|
|
|
|
---
|
|
|
|
## 11. Flexbox
|
|
|
|
HTML widgets support:
|
|
|
|
```css
|
|
display: flex;
|
|
display: inline-flex;
|
|
```
|
|
|
|
with a dedicated `FlexLayouter`.
|
|
|
|
The currently implemented flex state includes:
|
|
|
|
```text
|
|
flex-direction
|
|
flex-wrap
|
|
justify-content
|
|
align-items
|
|
align-content
|
|
align-self
|
|
|
|
flex-grow
|
|
flex-shrink
|
|
flex-basis
|
|
order
|
|
|
|
row-gap
|
|
column-gap
|
|
gap
|
|
```
|
|
|
|
Supported direction values include:
|
|
|
|
```text
|
|
row
|
|
row-reverse
|
|
column
|
|
column-reverse
|
|
```
|
|
|
|
Wrapping includes:
|
|
|
|
```text
|
|
nowrap
|
|
wrap
|
|
wrap-reverse
|
|
```
|
|
|
|
The layouter handles multiple flex lines, grow/shrink distribution, gaps, alignment, auto margins,
|
|
baseline alignment, order, percentage flex bases, intrinsic measurement, and stretching.
|
|
|
|
Children of flex containers are blockified for layout, including inline children.
|
|
|
|
### Important distinction
|
|
|
|
Flexbox belongs to the HTML formatting layer.
|
|
|
|
Do not replace a normal application `<hbox>` with:
|
|
|
|
```css
|
|
display: flex;
|
|
```
|
|
|
|
unless the subtree is intentionally HTML content.
|
|
|
|
For normal application UI, `UILinearLayout` remains the canonical row/column layout.
|
|
|
|
---
|
|
|
|
## 12. CSS Grid
|
|
|
|
HTML widgets support:
|
|
|
|
```css
|
|
display: grid;
|
|
display: inline-grid;
|
|
```
|
|
|
|
through `GridLayouter`.
|
|
|
|
The current grid model supports properties including:
|
|
|
|
```text
|
|
grid-template-rows
|
|
grid-template-columns
|
|
grid-template-areas
|
|
|
|
grid-auto-rows
|
|
grid-auto-columns
|
|
grid-auto-flow
|
|
|
|
grid-row-start
|
|
grid-row-end
|
|
grid-column-start
|
|
grid-column-end
|
|
|
|
grid-row
|
|
grid-column
|
|
grid-area
|
|
|
|
justify-items
|
|
justify-self
|
|
align-items
|
|
align-self
|
|
|
|
row-gap
|
|
column-gap
|
|
gap
|
|
|
|
order
|
|
```
|
|
|
|
The track model supports:
|
|
|
|
```text
|
|
fixed lengths
|
|
percentages
|
|
fr tracks
|
|
auto
|
|
min-content
|
|
max-content
|
|
fit-content(...)
|
|
minmax(...)
|
|
repeat(...)
|
|
auto-fill
|
|
auto-fit
|
|
named lines
|
|
template areas
|
|
implicit tracks
|
|
```
|
|
|
|
Grid items support definite placement, spans, automatic placement, dense auto-flow, intrinsic track
|
|
sizing, and alignment.
|
|
|
|
### Native `UIGridLayout` is unrelated
|
|
|
|
Do not confuse:
|
|
|
|
```text
|
|
UIGridLayout
|
|
```
|
|
|
|
with:
|
|
|
|
```text
|
|
display: grid
|
|
```
|
|
|
|
`UIGridLayout` is a native eepp repeated-cell layout.
|
|
|
|
CSS Grid is implemented by the HTML compatibility layer.
|
|
|
|
They have different APIs, sizing rules, and intended uses.
|
|
|
|
---
|
|
|
|
## 13. Tables
|
|
|
|
HTML tables use dedicated HTML widgets and `TableLayouter`.
|
|
|
|
Supported structural elements include:
|
|
|
|
```text
|
|
table
|
|
thead
|
|
tbody
|
|
tfoot
|
|
tr
|
|
th
|
|
td
|
|
```
|
|
|
|
The table implementation includes:
|
|
|
|
```text
|
|
intrinsic column sizing
|
|
table-layout: auto
|
|
table-layout: fixed
|
|
cell padding
|
|
cell spacing
|
|
colspan
|
|
row/cell sizing
|
|
```
|
|
|
|
Table layout is not implemented by native `UIGridLayout`.
|
|
|
|
If the source content is HTML tabular content, use HTML table semantics.
|
|
|
|
If the application is building an interactive application data view, prefer native widgets such as
|
|
`UITableView` or `UITreeView`.
|
|
|
|
---
|
|
|
|
## 14. Floats and `clear`
|
|
|
|
HTML widgets support:
|
|
|
|
```css
|
|
float: left;
|
|
float: right;
|
|
float: none;
|
|
|
|
clear: left;
|
|
clear: right;
|
|
clear: both;
|
|
```
|
|
|
|
Floats participate in block/inline document formatting and create text exclusions so following
|
|
inline content can wrap around them.
|
|
|
|
Floated inline elements are blockified for layout.
|
|
|
|
Floats also establish a block formatting context where applicable.
|
|
|
|
These semantics exist for document layout and should not be used as a general native application
|
|
placement system.
|
|
|
|
---
|
|
|
|
## 15. Positioned layout
|
|
|
|
The HTML property system recognizes:
|
|
|
|
```css
|
|
position: static;
|
|
position: relative;
|
|
position: absolute;
|
|
position: fixed;
|
|
position: sticky;
|
|
```
|
|
|
|
### Absolute positioning
|
|
|
|
`absolute` elements are removed from normal flow.
|
|
|
|
The containing block is selected from the nearest positioned HTML ancestor, with root fallback.
|
|
|
|
Insets are supported:
|
|
|
|
```css
|
|
top
|
|
right
|
|
bottom
|
|
left
|
|
```
|
|
|
|
including percentage values where the containing block has the required definite size.
|
|
|
|
Opposing insets can determine the used size of an auto-sized positioned box.
|
|
|
|
Auto margins are also handled in the positioned constraint equation.
|
|
|
|
### Fixed positioning
|
|
|
|
`fixed` elements are positioned against the relevant scroll/document viewport rather than ordinary
|
|
normal flow and are updated when scrolling changes.
|
|
|
|
### Sticky positioning
|
|
|
|
`sticky` participates in normal flow and is adjusted relative to a scroll viewport while respecting
|
|
the containing block.
|
|
|
|
Current sticky handling focuses on vertical top/bottom constraints.
|
|
|
|
### Relative positioning
|
|
|
|
`relative` currently participates in the positioned-element model, including containing-block and
|
|
stacking behavior.
|
|
|
|
Do not assume complete browser parity for relative `top/right/bottom/left` displacement; the current
|
|
implementation's explicit inset positioning logic is primarily implemented for absolute/fixed and
|
|
sticky positioning.
|
|
|
|
---
|
|
|
|
## 16. `z-index` and paint order
|
|
|
|
The HTML layer has CSS-aware paint ordering rather than relying only on raw widget child order.
|
|
|
|
The current model distinguishes categories broadly corresponding to the supported CSS stacking
|
|
subset:
|
|
|
|
```text
|
|
negative positioned/z-index content
|
|
normal-flow content
|
|
floats
|
|
positioned auto/zero content
|
|
positive positioned/z-index content
|
|
```
|
|
|
|
`z-index` applies to positioned elements and to flex/grid items where supported.
|
|
|
|
The implementation supports stacking groups for:
|
|
|
|
```text
|
|
fixed/sticky elements
|
|
positioned elements with applicable z-index
|
|
flex/grid items with applicable z-index
|
|
```
|
|
|
|
This is intentionally a supported subset of browser stacking-context behavior, not a claim of full
|
|
CSS Appendix E parity.
|
|
|
|
---
|
|
|
|
## 17. CSS sizing and the box model
|
|
|
|
HTML widgets support browser-style CSS sizing properties:
|
|
|
|
```css
|
|
width
|
|
height
|
|
min-width
|
|
min-height
|
|
max-width
|
|
max-height
|
|
|
|
margin
|
|
padding
|
|
border
|
|
box-sizing
|
|
```
|
|
|
|
`box-sizing` supports:
|
|
|
|
```text
|
|
content-box
|
|
border-box
|
|
```
|
|
|
|
For HTML widgets, `width` and `height` are interpreted through the CSS box model rather than merely
|
|
as raw native widget dimensions.
|
|
|
|
This is one reason the HTML compatibility layer should remain conceptually separate from normal
|
|
native application layout.
|
|
|
|
---
|
|
|
|
## 18. Percentage sizing uses containing blocks
|
|
|
|
HTML percentage sizing is resolved against CSS containing-block dimensions.
|
|
|
|
This applies to relevant properties such as:
|
|
|
|
```text
|
|
width
|
|
height
|
|
margin
|
|
padding
|
|
position offsets
|
|
flex-basis
|
|
grid tracks
|
|
```
|
|
|
|
The implementation also distinguishes cases where percentage height cannot resolve because the
|
|
containing block does not have a definite height.
|
|
|
|
In those cases, the HTML layer avoids treating the percentage as an ordinary fixed native
|
|
dimension.
|
|
|
|
The root document uses the document viewport as the initial containing block for relevant root/body
|
|
calculations.
|
|
|
|
---
|
|
|
|
## 19. Intrinsic sizing
|
|
|
|
The HTML layout layer has explicit intrinsic sizing support.
|
|
|
|
Concepts used internally include:
|
|
|
|
```text
|
|
minimum intrinsic width
|
|
maximum intrinsic width
|
|
min-content
|
|
max-content
|
|
fit-content
|
|
shrink-to-fit
|
|
```
|
|
|
|
These are used by block, flex, grid, table, replaced-element, and out-of-flow layout.
|
|
|
|
This is different from native eepp `WrapContent`.
|
|
|
|
They may eventually produce similar-looking results, but they are not the same algorithm.
|
|
|
|
Do not explain HTML `min-content` or `max-content` in terms of native `SizePolicy`.
|
|
|
|
---
|
|
|
|
## 20. Auto margins
|
|
|
|
HTML formatting contexts implement context-specific auto-margin behavior.
|
|
|
|
Examples include:
|
|
|
|
- horizontal centering of normal-flow blocks;
|
|
- free-space absorption in flex layouts;
|
|
- item alignment behavior in grid/flex;
|
|
- auto margins in positioned constraint equations.
|
|
|
|
This is distinct from ordinary native-layout auto-margin handling.
|
|
|
|
The HTML layer resolves used margins for the current formatting role without treating every
|
|
`margin: auto` as the same generic layout operation.
|
|
|
|
---
|
|
|
|
## 21. Overflow is only partially browser-equivalent
|
|
|
|
The CSS property is recognized:
|
|
|
|
```css
|
|
overflow: visible;
|
|
overflow: hidden;
|
|
overflow: auto;
|
|
overflow: scroll;
|
|
```
|
|
|
|
For HTML widgets, non-`visible` overflow also establishes a block formatting context.
|
|
|
|
However, the underlying native widget behavior currently maps:
|
|
|
|
```text
|
|
hidden
|
|
auto
|
|
scroll
|
|
```
|
|
|
|
to clipping of the widget content box.
|
|
|
|
It does **not** create an independent browser-like scroll container for every arbitrary HTML
|
|
element.
|
|
|
|
`UIWebView` itself provides document scrolling through its native `UIScrollView`.
|
|
|
|
Also note that `overflow-x` and `overflow-y` currently alias the same `overflow` property; they are
|
|
not independent axes yet.
|
|
|
|
This is an important compatibility limitation.
|
|
|
|
---
|
|
|
|
## 22. `visibility` is not fully browser-equivalent
|
|
|
|
HTML widgets recognize:
|
|
|
|
```css
|
|
visibility: visible;
|
|
visibility: hidden;
|
|
visibility: collapse;
|
|
```
|
|
|
|
The current implementation maps `hidden` to native widget visibility.
|
|
|
|
As a result, `visibility: hidden` does not currently guarantee the browser behavior of preserving
|
|
the element's normal-flow geometry while suppressing painting.
|
|
|
|
Flex layout has specific handling for `visibility: collapse`, but this should not be interpreted as
|
|
complete `visibility` parity across every formatting context.
|
|
|
|
When precise browser-compatible visibility geometry matters, verify the current behavior rather
|
|
than assuming browser semantics.
|
|
|
|
---
|
|
|
|
## 23. Text formatting and inheritance
|
|
|
|
HTML text is rendered through `UIRichText`, `UITextSpan`, and `UITextNode`.
|
|
|
|
Supported text-oriented CSS includes concepts such as:
|
|
|
|
```text
|
|
font-family
|
|
font-size
|
|
font-style
|
|
font-weight
|
|
color
|
|
text-decoration
|
|
text-align
|
|
text-indent
|
|
text-transform
|
|
line-height
|
|
white-space
|
|
white-space-collapse
|
|
tab-size
|
|
text shadow/stroke
|
|
```
|
|
|
|
Relevant properties participate in eepp's current inheritance system.
|
|
|
|
HTML inline elements therefore behave much more like document text than ordinary independent native
|
|
application widgets.
|
|
|
|
The exact supported property set is documented in
|
|
[`css_specification.md`](css_specification.md).
|
|
|
|
---
|
|
|
|
## 24. Text selection is document-wide
|
|
|
|
`UIWebView` and `UIMarkdownView` both provide a `UITextSelectionController`.
|
|
|
|
Selection can cross individual rich-text/span widget boundaries rather than being limited to a
|
|
single widget.
|
|
|
|
HTML widgets support:
|
|
|
|
```css
|
|
user-select: auto;
|
|
user-select: text;
|
|
user-select: none;
|
|
user-select: contain;
|
|
user-select: all;
|
|
```
|
|
|
|
`-webkit-user-select` is accepted as an alias.
|
|
|
|
The default used behavior is text-selectable unless inherited `none` or `all` semantics change it.
|
|
|
|
This is one of the important differences between document content and ordinary isolated text
|
|
widgets.
|
|
|
|
---
|
|
|
|
## 25. Links and navigation
|
|
|
|
`<a>` is represented by `UIAnchorSpan`.
|
|
|
|
Anchor activation uses the scene navigation path.
|
|
|
|
Inside a `UIWebView`, navigation requests are intercepted by the embedded document scene and routed
|
|
back into the owning `UIWebView`, including relative URL resolution.
|
|
|
|
This means ordinary links can navigate the current web view.
|
|
|
|
`NavigationRequest` carries the source node, mouse buttons, and keyboard modifiers. Middle click,
|
|
the platform modifier plus left click, or an explicit `Target::NewTab` request emits
|
|
`Event::OnLinkOpenRequested` on the WebView. Subscribe to this event, open the resolved URI in a
|
|
new view, and call `UIWebView::LinkOpenEvent::accept()` to handle it. Unhandled requests navigate
|
|
the current view. Applications add their own link menu actions through `OnCreateContextMenu`;
|
|
`ContextMenuEvent::getTarget()` identifies the clicked document node.
|
|
|
|
`getTitle()` returns the parsed HTML document title. `onTitleChanged()` reports the title after
|
|
loading, including an empty title for pages without one. The `ui_html` example uses it for tab labels
|
|
and falls back to the host or URL. Tabs cap their width at 200dp and truncate long titles with ellipsis.
|
|
The example enables `UITabWidgetSplitter::setShowTabBarWhenSplit(true)` to keep each pane's tab bar
|
|
visible while split. This option is disabled by default for other splitter users.
|
|
|
|
`<link rel="icon" href="...">` (including `rel="shortcut icon"`) loads the declared favicon through
|
|
the document's shared image cache. Relative URLs resolve against the document URL, and SVG icons
|
|
are supported. `Event::OnFaviconChanged` carries a `UIWebView::FaviconEvent` with the loaded texture;
|
|
an empty icon clears the previous document's favicon. Responses from an older navigation are ignored.
|
|
The `ui_html` example displays the texture as a 16dp tab icon.
|
|
|
|
`UIWebView` maintains its own navigation history.
|
|
|
|
`UIMarkdownView` follows local `.md` and `.markdown` links in the same view by default. Supply
|
|
the source filename when rendering an editor buffer so relative links resolve from that document:
|
|
|
|
```cpp
|
|
markdownView->loadFromString( markdown, "/project/README.md" );
|
|
// Or load the document from disk (uses the scene's worker pool when available):
|
|
markdownView->loadFromFile( "/project/README.md" );
|
|
```
|
|
|
|
Both `docs/intro.md` and `file://docs/intro.md` resolve relative to the source document;
|
|
`file:///project/docs/intro.md` is absolute. Subsequent links resolve from the newly loaded document.
|
|
Without a source filename, links use the enclosing scene's base URI. Copy Link uses the same
|
|
resolution. `getDocumentPath()` reports the displayed source filename. Failed reads preserve the
|
|
current document and emit `OnNavigationError`; successful reads emit `OnNavigationCompleted`, both
|
|
with `UIMarkdownView::NavigationEvent`. Replacing content cancels pending navigation.
|
|
|
|
Call `setFollowLocalLinks(false)` to disable default local navigation. Every link first emits
|
|
`OnLinkOpenRequested`, whose `UIMarkdownView::LinkOpenEvent::request` contains the resolved URI,
|
|
source node, mouse buttons, modifiers, and target. A consumer can open a new tab or implement another
|
|
flow and call `accept()` to prevent default handling. Middle click and the platform modifier plus
|
|
left click request `NavigationRequest::Target::NewTab`; consumers can also call `navigate()` with
|
|
an explicit target. Unaccepted local new-tab requests open in the same view. Other links continue
|
|
through the enclosing scene's navigation handler. No tab UI or navigation history is built into
|
|
the Markdown view.
|
|
|
|
Markdown views register their navigation handlers with
|
|
`UISceneNode::setNavigationInterceptorCb(root, callback)`, scoped to their own widget subtree.
|
|
Scoped callbacks run from the closest scope outward; returning `false` falls through to the next
|
|
scope and then to the scene-wide interceptor. Registering a scope does not replace the scene-wide
|
|
callback. A scope must belong to the scene's tree when registered. An empty callback unregisters
|
|
a scope, including one that has already moved out of the tree. The Markdown view manages registration
|
|
when it moves between scenes or is destroyed. The scoped overload returns `true` for registration,
|
|
replacement, or removal, and `false` for invalid roots or removal of a missing registration.
|
|
|
|
`UIMarkdownView` uses the same shortcuts through its enclosing `UIScrollView`; disable them on
|
|
that scroll view with `setEnableDefaultKeybindings(false)`.
|
|
|
|
`UIScrollableMarkdownView` provides the scroll container and owns a `UIMarkdownView` child. It is
|
|
declared in `uimarkdownview.hpp` and can also be created as `<ScrollableMarkdownView>` in XML layouts,
|
|
with inline Markdown text or CDATA. Configure the child through `getMarkdownView()`:
|
|
|
|
```cpp
|
|
auto* documentView = UIScrollableMarkdownView::New();
|
|
documentView->setParent( parent );
|
|
documentView->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
|
|
documentView->getMarkdownView()->loadFromFile( "/project/README.md" );
|
|
```
|
|
|
|
Successful file navigation resets both scrollbars to the start. String updates and failed loads
|
|
preserve scrolling. The wrapper implements `WidgetCommandExecuter`: register custom commands with
|
|
`setCommand()` and shortcuts with `getKeyBindings()`. Unhandled keys use the scroll view's default
|
|
shortcuts. Loading, link policy, selection, and navigation events belong to the Markdown child;
|
|
editor binding and session persistence remain application responsibilities.
|
|
|
|
History navigation is disabled by default. Call `setHistoryNavigationEnabled(true)` to enable it
|
|
and start history at the current named Markdown document. Disabling clears history and unregisters
|
|
the history commands and shortcuts; loading documents and following local links remain available.
|
|
Ecode explicitly enables history for its Markdown previews.
|
|
|
|
When enabled, the scrollable wrapper maintains history for named Markdown documents.
|
|
`goHistoryBack()` and `goHistoryForward()` traverse it; `canGoBack()` and `canGoForward()` report
|
|
available directions.
|
|
The `go-back` and `go-forward` commands default to `mod+[` and `mod+]`, using the platform's default
|
|
modifier. Once a direction is available, the document's context menu adds Go Back and Go Forward,
|
|
enabling each as appropriate. A successful new navigation discards the forward branch; updating the
|
|
current string buffer preserves it. Failed and canceled loads do not advance history. Traversal
|
|
reloads files by default; applications can override `loadHistoryDocument()` to render their current
|
|
buffer instead. Ecode uses this for its live source, including unsaved edits. History is kept for
|
|
the lifetime of the widget and is cleared when it loads an anonymous string document.
|
|
|
|
Default scrolling shortcuts are Space and Page Down (one viewport down), Shift+Space and Page Up
|
|
(one viewport up). Keys handled by a focused descendant do not reach the WebView. While text input is active,
|
|
Space scrolls only if its committed text reaches the WebView unhandled; custom controls can consume
|
|
it through `onTextInput()` like built-in editors. Call `setEnableDefaultKeybindings(false)` to disable scrolling
|
|
shortcuts, including the inherited arrow and Home/End bindings.
|
|
|
|
Anchor interaction also cooperates with document text selection so a completed text drag does not
|
|
accidentally activate the link.
|
|
|
|
---
|
|
|
|
## 26. Forms
|
|
|
|
The compatibility layer includes basic form support.
|
|
|
|
Supported form-oriented widgets currently include:
|
|
|
|
```text
|
|
form
|
|
input
|
|
textarea
|
|
button
|
|
label
|
|
```
|
|
|
|
`UIHTMLInput` hosts native eepp controls internally.
|
|
|
|
Recognized input types include:
|
|
|
|
```text
|
|
button
|
|
checkbox
|
|
color
|
|
date
|
|
datetime-local
|
|
email
|
|
file
|
|
hidden
|
|
image
|
|
month
|
|
number
|
|
password
|
|
radio
|
|
range
|
|
reset
|
|
search
|
|
submit
|
|
tel
|
|
text
|
|
time
|
|
url
|
|
week
|
|
```
|
|
|
|
Not every type has a specialized native implementation. Unsupported/specialized types fall back to
|
|
the generic text-input implementation unless explicitly mapped otherwise.
|
|
|
|
Current explicit native mappings include:
|
|
|
|
```text
|
|
button / submit / reset -> UIPushButton
|
|
checkbox -> UICheckBox
|
|
hidden -> no visible child
|
|
date -> UIDatePicker
|
|
time -> UITimePicker
|
|
datetime-local -> UIDateTimePicker
|
|
number -> UISpinBox
|
|
password -> password text input
|
|
radio -> UIRadioButton
|
|
other text-like types -> UIHTMLTextInput
|
|
```
|
|
|
|
Form controls use light user-agent defaults from `getHTMLDocumentDefaultsCSS()` in
|
|
`uiwidgetcreator.cpp`, independently of the application's native theme. Author CSS styles the
|
|
HTML control host; anonymous implementation parts retain their private defaults. Temporal controls
|
|
have intrinsic text/placeholder sizing, so they remain usable without an authored width.
|
|
|
|
`textarea` uses a `UITextEdit`-based implementation with `rows` and `cols` intrinsic sizing.
|
|
|
|
Forms collect named control values and can submit navigation requests.
|
|
|
|
Temporal inputs sanitize invalid value strings to empty and submit normalized ISO values independently
|
|
of their display locale. They support `min`, `max`, `step`, `required`, `readonly`, and `disabled`.
|
|
Range validation never silently changes the supplied value; reversed time ranges wrap midnight.
|
|
`UIHTMLInput::getValidity()` exposes the implemented temporal validity flags. `UIHTMLForm::requestSubmit()`
|
|
and submit-button activation validate these controls, while direct `submit()` bypasses validation.
|
|
Disabled temporal controls are excluded from form data, and named empty temporal controls submit an
|
|
empty string. See [date/time pickers](ui_date_time_pickers.md) for APIs and the supported subset.
|
|
|
|
An omitted or empty form `action` submits to the full current document URL, preserving its query.
|
|
|
|
Supported submission encodings include:
|
|
|
|
```text
|
|
application/x-www-form-urlencoded
|
|
multipart/form-data
|
|
text/plain
|
|
```
|
|
|
|
GET and POST submission paths are implemented.
|
|
|
|
---
|
|
|
|
## 27. Labels
|
|
|
|
`<label for="...">` is interactive.
|
|
|
|
The label resolves the referenced widget and can activate supported controls such as checkboxes and
|
|
radio buttons.
|
|
|
|
Keyboard activation is also supported.
|
|
|
|
This behavior is implemented natively rather than through JavaScript.
|
|
|
|
---
|
|
|
|
## 28. Images and SVG
|
|
|
|
HTML images use `UIHTMLImage`.
|
|
|
|
They participate as replaced elements with intrinsic sizing and CSS width/height behavior.
|
|
|
|
`<svg>` is backed by `UISvg` marked as an HTML element so it can participate in HTML sizing/layout.
|
|
|
|
Resource URLs can be:
|
|
|
|
```text
|
|
file URLs
|
|
HTTP/HTTPS URLs
|
|
data URLs where supported
|
|
eepp resource locators
|
|
```
|
|
|
|
Relative document/style resources are resolved against the relevant document or stylesheet base URI.
|
|
|
|
---
|
|
|
|
## 29. Stylesheets and resource loading
|
|
|
|
HTML documents can contain:
|
|
|
|
```html
|
|
<style>
|
|
...
|
|
</style>
|
|
```
|
|
|
|
and stylesheet links:
|
|
|
|
```html
|
|
<link rel="stylesheet" href="...">
|
|
```
|
|
|
|
`UIWebView` can load local and HTTP/HTTPS stylesheets.
|
|
|
|
Relative stylesheet resource URLs are resolved against the stylesheet/document base URI when one is
|
|
available.
|
|
|
|
Supported stylesheet at-rules include those documented in
|
|
[`css_specification.md`](css_specification.md), including:
|
|
|
|
```text
|
|
@import
|
|
@media
|
|
@font-face
|
|
@keyframes
|
|
```
|
|
|
|
`@font-face` can load local, data-backed, and HTTP/HTTPS font resources through the document scene.
|
|
|
|
---
|
|
|
|
## 30. Media queries
|
|
|
|
The same media-query engine used elsewhere in eepp is available to HTML document styles.
|
|
|
|
Supported features are documented in
|
|
[`css_specification.md`](css_specification.md).
|
|
|
|
Document layout should still rely primarily on normal CSS layout mechanisms such as:
|
|
|
|
```text
|
|
block flow
|
|
flex wrapping
|
|
grid tracks
|
|
intrinsic sizing
|
|
```
|
|
|
|
rather than reproducing layout entirely with breakpoint-specific absolute dimensions.
|
|
|
|
---
|
|
|
|
## 31. HTML visibility and document extent inside `UIWebView`
|
|
|
|
`UIWebView` maintains document viewport and content extent separately.
|
|
|
|
The document scene is updated when:
|
|
|
|
- the web view changes size;
|
|
- scrollbars appear/disappear;
|
|
- HTML layout changes;
|
|
- resources load and alter geometry;
|
|
- viewport-dependent percentages need recomputation.
|
|
|
|
The root `html` and `body` boxes are synchronized with the document viewport while still allowing
|
|
content to grow beyond it.
|
|
|
|
Out-of-flow content can contribute to the final scrollable document extent when appropriate.
|
|
|
|
Fixed-position content is treated separately from normal scrollable document extent.
|
|
|
|
---
|
|
|
|
## 32. Root `html` / `body` behavior is special
|
|
|
|
The root document boxes have browser-oriented special handling.
|
|
|
|
`body` maintains a minimum height based on:
|
|
|
|
```text
|
|
viewport height
|
|
its local min-height
|
|
document content extent
|
|
```
|
|
|
|
The root `html` box is kept at least large enough to cover the document viewport/content.
|
|
|
|
The body's background may propagate to the root HTML element when the root background is otherwise
|
|
transparent.
|
|
|
|
These rules should not be inferred from ordinary native `UILayout` behavior.
|
|
|
|
---
|
|
|
|
## 33. Paint order and hit testing follow the HTML layer
|
|
|
|
HTML positioned/floating content can be painted in an order different from raw widget child order.
|
|
|
|
Hit testing follows the corresponding HTML paint traversal when required.
|
|
|
|
This matters for:
|
|
|
|
```text
|
|
z-index
|
|
positioned descendants
|
|
floats
|
|
overlapping HTML content
|
|
flex/grid order
|
|
```
|
|
|
|
Do not debug overlapping HTML content by looking only at the native child insertion order.
|
|
|
|
Use the actual HTML layout/paint state.
|
|
|
|
---
|
|
|
|
## 34. Structural CSS selectors can react to document structure
|
|
|
|
The selector engine supports structural selectors such as:
|
|
|
|
```text
|
|
:first-child
|
|
:last-child
|
|
:nth-child(...)
|
|
:nth-last-child(...)
|
|
:first-of-type
|
|
:last-of-type
|
|
:nth-of-type(...)
|
|
:nth-last-of-type(...)
|
|
:only-child
|
|
:only-of-type
|
|
:empty
|
|
:not(...)
|
|
```
|
|
|
|
Structural and relationship-dependent selectors are treated as volatile where needed so relevant
|
|
widgets can be restyled when structure/state changes.
|
|
|
|
This is especially important for HTML-like document styling.
|
|
|
|
---
|
|
|
|
## 35. CSS state rollback still uses eepp's common style engine
|
|
|
|
HTML widgets share the same `UIStyle` implementation as native widgets.
|
|
|
|
That means the current limitation around properties that stop matching a pseudo-class/volatile
|
|
selector also applies to HTML content.
|
|
|
|
eepp currently preserves prior values through a best-effort stateless/current-value fallback rather
|
|
than a complete browser-style computed-cascade rollback model.
|
|
|
|
---
|
|
|
|
## 36. Compatibility does not mean complete browser parity
|
|
|
|
The HTML layer intentionally implements a useful subset of browser layout and interaction behavior.
|
|
|
|
It should not be described as a fully compliant browser engine.
|
|
|
|
Examples of known boundaries include:
|
|
|
|
```text
|
|
no JavaScript runtime
|
|
only registered HTML elements are materialized
|
|
overflow does not create arbitrary per-element scroll containers
|
|
overflow-x / overflow-y are not independent yet
|
|
visibility semantics are not fully browser-equivalent
|
|
relative positioning should not be assumed to implement every browser offset behavior
|
|
stacking/paint order is a supported subset
|
|
form controls map onto native eepp widgets
|
|
CSS state rollback is not a complete computed-style rollback model
|
|
```
|
|
|
|
Other browser features should be considered supported only when they are implemented and tested in
|
|
eepp.
|
|
|
|
When compatibility behavior matters, the implementation and HTML-specific unit tests are the source
|
|
of truth.
|
|
|
|
---
|
|
|
|
## 37. Where to look in the source
|
|
|
|
The main implementation is concentrated in:
|
|
|
|
```text
|
|
HTML host / navigation:
|
|
include/eepp/ui/uiwebview.hpp
|
|
src/eepp/ui/uiwebview.cpp
|
|
|
|
HTML widget semantics:
|
|
include/eepp/ui/uihtmlwidget.hpp
|
|
src/eepp/ui/uihtmlwidget.cpp
|
|
|
|
HTML parsing:
|
|
include/eepp/ui/tools/htmlformatter.hpp
|
|
src/eepp/ui/tools/htmlformatter.cpp
|
|
|
|
formatting contexts:
|
|
src/eepp/ui/blocklayouter.cpp
|
|
src/eepp/ui/inlinelayouter.cpp
|
|
src/eepp/ui/flexlayouter.cpp
|
|
src/eepp/ui/gridlayouter.cpp
|
|
src/eepp/ui/tablelayouter.cpp
|
|
|
|
text:
|
|
src/eepp/ui/uirichtext.cpp
|
|
src/eepp/ui/uitextspan.cpp
|
|
|
|
HTML widgets:
|
|
src/eepp/ui/uihtmlimage.cpp
|
|
src/eepp/ui/uihtmlinput.cpp
|
|
src/eepp/ui/uihtmltextarea.cpp
|
|
src/eepp/ui/uihtmlform.cpp
|
|
src/eepp/ui/uihtmltable.cpp
|
|
src/eepp/ui/uihtmldetails.cpp
|
|
src/eepp/ui/uihtmllistitem.cpp
|
|
|
|
Markdown:
|
|
src/eepp/ui/uimarkdownview.cpp
|
|
|
|
HTML element registration/default CSS:
|
|
src/eepp/ui/uiwidgetcreator.cpp
|
|
```
|
|
|
|
The most useful tests are under:
|
|
|
|
```text
|
|
src/tests/unit_tests/uihtml_tests.cpp
|
|
src/tests/unit_tests/uihtml_flex_test.cpp
|
|
src/tests/unit_tests/uihtml_grid_test.cpp
|
|
src/tests/unit_tests/uihtml_float_tests.cpp
|
|
src/tests/unit_tests/uihtml_position_tests.cpp
|
|
src/tests/unit_tests/uihtmlform_tests.cpp
|
|
src/tests/unit_tests/uiwebview_tests.cpp
|
|
```
|
|
|
|
---
|
|
|
|
## 38. Related documentation
|
|
|
|
- [`ui_introduction.md`](ui_introduction.md) — introduction to the eepp UI system.
|
|
- [`ui_authoring.md`](ui_authoring.md) — recommended native application UI mental model.
|
|
- [`ui_layout_reference.md`](ui_layout_reference.md) — exact native layout semantics.
|
|
- [`ui_css_for_applications.md`](ui_css_for_applications.md) — CSS conventions for ordinary
|
|
application widgets.
|
|
- [`css_specification.md`](css_specification.md) — CSS property, selector, value, and at-rule
|
|
reference.
|
|
- [`ui_inspector.md`](ui_inspector.md) — runtime UI inspection and automation protocol.
|
|
- [`ui_databinding.md`](ui_databinding.md) — UI data binding.
|
|
- [`ui_charts.md`](ui_charts.md) — charting widgets and chart-specific behavior.
|
|
|
|
The practical rule is simple:
|
|
|
|
> Use native eepp layouts to build applications. Use the HTML compatibility layer when the content
|
|
> itself is HTML/Markdown/document-oriented.
|