* 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 页面
4.1 KiB
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:ResolveNineSlicefollows CSSborder-image(slices in source-image pixels, widths in DIP);ResolveContentPaddingmeasurescontent_insets_dipfrom the panel's outer edge and never below the border width;SplitDecorationsstably sorts decorations and splits them atkDecorationFrontZIndex(1) into a layer below and a layer above the card. - In
CandidatePresenter's scene the card and twoCandidateSkinOverlaylayers share one cell: back decorations, card, front decorations. Overlay layers measure 0 and do not hit test. The panel is drawn bymsimeui::Card::SetBackgroundNineSlice; with a panel image the card's fill, stroke, radius and shadow are cleared.line_gap_dipbecomes the preedit row's bottom margin, so list/pager spacing is unaffected.outer_insets_dipbecomes extra window space around the card.anchorandoffset_*_dip: positive values move right and down. - Animation: images are fetched through
DeviceResources::GetImageFrame.Presentsamples the animation clock withBeginFrame, renders, then readsScene::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. WithSPI_GETCLIENTAREAANIMATIONoff, images are drawn still (first frame), as for v1 skins.