* feat(ui): 新增 APNG/GIF 动图解码与动画帧时钟 AnimatedImage 按 APNG 规范解析 acTL/fcTL/fdAT 并校验序号、CRC 与帧边界,逐帧重建 PNG 交给 WIC 解码后按 dispose_op/blend_op 合成;GIF 走 WIC 多帧解码。延时规则与浏览器一致,超限或损坏的动画退回静态首帧。 DeviceResources::GetImageFrame 按动画时钟取帧并汇报下一次换帧时刻,动图帧按 64 MB 预算缓存;Scene 与 Window 据此按需重绘,可整体关闭动画。DrawNineSlice 按 CSS border-image 语义区分源切片与目标边宽、支持 fill,并用夹取画刷消除接缝渗色。 * feat(server): 新增 canvas 基础皮肤并要求 v2 皮肤基于它 canvas 是全贴图基底:透明面板、无描边、无圆角、无阴影,外观来自九宫格面板图与挂件。它只能作为外部皮肤的 base,不进内置皮肤列表;v1 皮肤用它直接报错。 schema_version = 2 而 base 不是 canvas 的皮肤按 v1 加载、忽略全部 v2 字段,并在扫描结果里记一条问题。v2 字段补齐校验:图片限 .png/.apng/.gif/.webp,fill 必须是布尔,偏移与 z_index 有范围,挂件最多 32 层。 * feat(server): D2D 候选窗补齐 v2 九宫格、挂件分层与动图 canvas 皮肤在 D2D 候选窗里按 CSS border-image 语义绘制九宫格面板:切片以源图像素计、边宽以 DIP 计、fill = false 不画中心;有面板图时卡片的底色、描边、圆角与阴影让给贴图。content_insets_dip 从面板外缘量起且不小于边框宽度,line_gap_dip 只作用于预编辑行与候选之间。 挂件拆成卡片前后两层:z_index < 1 在面板之下,其余在面板之上,同层按 z_index 与声明顺序稳定排序;图片在框内等比居中。动图按场景给出的下一次换帧时刻排一次性定时器续帧,只在候选窗显示时运行,隐藏、换皮肤时停;系统关闭动画效果时只显示首帧,v1 皮肤保持静态。 设置页原生预览认得 canvas 基底并绘制面板图。 * feat(examples): 新增基于 canvas 的 v2 全贴图皮肤样例 canvas-demo 用 2 倍九宫格面板、面板下层的叶子挂件和面板上层循环播放的 APNG 星光演示 v2 皮肤,素材均为程序生成的几何图形,随目录以 MIT 授权。样例测试同步校验 schema 2 与 canvas 互为前提、v2 图片扩展名与数值范围。 * docs(examples): 说明 canvas 基底、v2 九宫格与挂件分层及动图规则 schema 说明去掉「仅 WebView2」,写明 v2 必须以 canvas 为 base、canvas 只能当 base;九宫格切片按源图像素、边宽按 DIP,content_insets_dip 不小于边宽,line_gap_dip 只管预编辑行与候选之间;挂件以 z_index 1 为界分在面板上下两层;动图格式、帧时长、上限与系统减少动画时的行为。server/docs/ui-backends.md 与 skins/README.md 同步更新。 * docs(server): 候选窗与皮肤目录的注释不再引用已删除的 WebView2 页面
64 lines
4.1 KiB
Markdown
64 lines
4.1 KiB
Markdown
# UI ownership
|
||
|
||
| Surface | Renderer | Owner |
|
||
|---|---|---|
|
||
| Candidate, floating toolbar, tray menu | msimeui native Direct2D/DirectWrite | `src/window/` presenters in the Server process |
|
||
| Settings | msimeui native Direct2D/DirectWrite | `src/settings/native/` in the separate `MetasequoiaImeSettings.exe` |
|
||
| Keyboard, handwriting, emoji and voice panels | Their existing native application/presenter | Shared actions/configuration stay in Server; panels do not own input sessions |
|
||
|
||
Direct2D is the only renderer. The WebView2 small windows, the WebView2 settings host and
|
||
the `ui-html/` pages have been removed, together with the `appearance.ui_backend` and
|
||
`appearance.settings_ui_backend` configuration keys; existing values are dropped by the
|
||
template merge on upgrade.
|
||
|
||
The candidate worker resolves output text, auxiliary codes, source badges and
|
||
translations once into `CandidateViewItem`, and the native renderer consumes these
|
||
values as plain text. Clicks enter the existing `EnqueueCandidateUiAction` queue with the
|
||
focus owner checks and action policy. The ten-entry mouse range is distinct from the
|
||
1–9 keyboard shortcuts. New business behavior belongs in shared actions/session/view
|
||
models, not in a presenter.
|
||
|
||
## Settings window
|
||
|
||
`MetasequoiaImeSettings.exe` draws its window with msimeui in `src/settings/native/`.
|
||
The window speaks the message contract in `engine/contracts/webview/` (the name is
|
||
historical): it receives `configSnapshot` and the response messages as JSON and posts
|
||
`configUpdate` and the request messages through `HandleClientMessage` in
|
||
`settings_app.cpp`, so config paths are mapped in one place. Its image assets live in
|
||
`server/assets/settings/` and are installed to `<data dir>\assets\settings\`.
|
||
|
||
The pages were ported one to one from the former HTML/CSS settings page: each page
|
||
builder in `native_page_*.cpp` names the partial and module it came from, and the
|
||
controls in `native_settings_controls.*` name the CSS rule they mirror. Those sources
|
||
remain in git history under `ui-html/webview2/settings/ime-settings/src/`.
|
||
|
||
Sciter is not an active product backend. The msimeui library owns generic controls and
|
||
rendering, never Server configuration, pipe sessions, dictionary access, or global
|
||
input state.
|
||
|
||
## v2 skins
|
||
|
||
`schema_version = 2` skins must use `base = "canvas"` (see `skin/candidate_skin_catalog.h`);
|
||
the fields are documented in `examples/skin-examples/schema/README.md`. `canvas` is the
|
||
full-texture base: transparent panel, no stroke, square corners, no shadow by default. It is
|
||
only usable as a base and is not part of `BuiltInIds()`.
|
||
|
||
- Geometry lives in `window/candidate_skin_layers.*` (pure arithmetic, no rendering) and is
|
||
shared by the candidate window and the settings preview: `ResolveNineSlice` follows CSS
|
||
`border-image` (slices in source-image pixels, widths in DIP); `ResolveContentPadding`
|
||
measures `content_insets_dip` from the panel's outer edge and never below the border width;
|
||
`SplitDecorations` stably sorts decorations and splits them at `kDecorationFrontZIndex` (1)
|
||
into a layer below and a layer above the card.
|
||
- In `CandidatePresenter`'s scene the card and two `CandidateSkinOverlay` layers share one
|
||
cell: back decorations, card, front decorations. Overlay layers measure 0 and do not hit
|
||
test. The panel is drawn by `msimeui::Card::SetBackgroundNineSlice`; with a panel image the
|
||
card's fill, stroke, radius and shadow are cleared. `line_gap_dip` becomes the preedit row's
|
||
bottom margin, so list/pager spacing is unaffected. `outer_insets_dip` becomes extra window
|
||
space around the card. `anchor` and `offset_*_dip`: positive values move right and down.
|
||
- Animation: images are fetched through `DeviceResources::GetImageFrame`. `Present` samples
|
||
the animation clock with `BeginFrame`, renders, then reads `Scene::GetNextFrameDeadline()`
|
||
and, only while the candidate window is shown, arms one one-shot coalescable timer
|
||
(`kCandidateAnimationTimerId`) that presents again. Hiding, a deferred show and a skin change
|
||
stop it; the clock restarts when the window goes from hidden to shown. With
|
||
`SPI_GETCLIENTAREAANIMATION` off, images are drawn still (first frame), as for v1 skins.
|