feat(canvas): 完善旧版 CanvasContext 跨端能力并统一触摸手势与 label 激活 - #306
Conversation
c16375e to
9dd5b29
Compare
|
@dos1in review |
35f9a8d to
d58e3fe
Compare
|
@dos1in 本来是想修改 Canvas 上的小问题,这下干脆把整个 Tap 事件按照微信小程序对齐了一遍。可以再 review 了 |
useTouchEvents.js#L26-L52
|
|
1. [P1] 判重改为按「页面 + 宿主组件实例 + canvas-id」在模块作用域的 新增 2. [P1] 动态切换 重装监听器这件事保留(passive 只能在注册时决定),但推迟到当前序列以 新增 3. [P1] iOS 在主线程解码并写入最大 32 MB 图片 解码 + 落盘抽成 同一个问题另外两端也有,一并改了(这两条不在 review 列表里):
Android 新增 5 例、iOS 新增 3 例单测,覆盖真实写盘产物、签名不匹配时不落盘、success/fail 各自的 complete 载荷,以及 iOS 的重活确实不在调用线程上完成。 4. [P2]
还有一处同源的偏离没动,想听下你的意见:微信的 验证:
|
|
|
第二轮四条已修( 你提的四条
自查另外发现的五条
已知未修runtime 在导出途中销毁时,Android/iOS 会把已写成的临时文件留在 tmp(回调本身正确丢弃)。Harmony 有 generation 可以顺手删,另两端没有等价 epoch,要检测得改 其余:单次文件 IO 无 deadline;Android/iOS 的 appId→锁表只增不减;iOS 的陈旧判定押在「 验证
新增行为测试都做了变异验证(去掉修复必须变红):让出重试 3 条、归属解析 2 条、getActions 守卫 1 条。 真机第一轮有两条红,都查了归属: |
|
|
第三轮四条和后续独立复审发现的问题都已闭环,最终修复在
本轮另外新增了两项实现与验证:
在此之后又做了一轮完整独立 review,继续修了 layout → backing store 预算绕过、动态 resolver、小游戏替换后的 render 资源残留、callback / RAF / ImageData 生命周期、iOS Unicode Base64 预算绕过,以及 Canvas2D setter/readback、save/restore/reset/resize 和旧 WebKit fallback。最终独立复查没有留下未闭环 finding。 验证:
|
7db3af6 to
9d08111
Compare
|
上一条之后又做了几轮独立复审,修复已经 amend 进同一个 commit(现为 1. 多指下的 原实现在第二根手指按下时立刻抑制 同时明确不采用 glass-easel 按 2. 同一个探针实测:越过位移阈值后,之后每一条 3. 节点卸载后仍会补造长按
4. HarmonyOS 编译回归 本 PR 给 5. JSSDK 重新生成 上面的手势改动落在 文档同步:触摸事件与手势第 1、3、6、7 节按上述语义重写;Canvas 运行架构补充了 |
旧版 wx.createCanvasContext() 补齐三端能力。canvas-id 按「页面 + 自定义组件实例」登记, 归属与 active 状态走 DOM property,不进入小程序事件的 target.dataset。组件根节点承载小程序 声明的 id、dataset 和布局,内部 HTMLCanvasElement 承载绘图,两者用共享的 DOM contract 显式 关联,SelectorQuery 的 node 不会误取 slot 里的 canvas。 绘制、像素读写与导出按真实 canvas 元素串行,不同 canvas 互不阻塞;作用域内的节点 lookup 单独 排队,避免后发请求越过还在等节点挂载的先发请求。Canvas 2D 状态以渲染层宿主 context 为权威, 逻辑层提供同步 optimistic getter 并以单调序号接收 readback,迟到反馈不覆盖新值;宿主缺少 reset() 时重设同尺寸 backing store 完成全量重置。 位图与 JSON 传输预算收拢到 @dimina/common 一处,组件 renderWidth/renderHeight、布局同步、 node width/height setter、离屏与小游戏创建、legacy 像素 API 和 canvasToTempFilePath 共用同一 组限制,超限在分配输出位图与编码之前失败。 Android、iOS、HarmonyOS 的导出请求绑定 app owner 与 runtime generation:退出或重启先推进 generation 并取消尚未开始的请求,已开始的继续占用并发与字节配额,旧 generation 的结果不投递、 已发布的文件立即删除,success/fail 与 complete 在同一串行域结算。 draw(reserve) 只保留像素、不保留绘图状态:渲染层每批开一层基线 save 帧,下批开始时弹回默认 样式、变换与裁剪区,画面不动;批内未配平的 restore() 停在批边界,弹不走基线帧。 触摸手势统一由 touchGestures 合成 tap/longpress/longtap/canceltap,按 owner 记账触点,不再 依赖全局 event.touches;label 默认不抑制内层组件的激活态。取消语义按微信实测对齐:越过位移 阈值后每条 touchmove 各发一条 canceltap,touchend 再比一次起终点距离、超阈值改发 canceltap, 这两条补发路径只在整段序列还没发过 canceltap 时生效;额外触点只停长按计时器,不取消先落手指 的 tap。节点卸载时进行中的序列仍等真实终态收口,但立即停掉长按计时器,不给已离树的节点补造 longpress/longtap。一个手势所有者只维护一条序列,不采用 glass-easel 按 identifier 逐触点 记账的模型。 DMPContainerBridgesModule 上移 currentAppId() 为 protected,Image/Video/Screen/Http 四个 子类删除各自逐字相同的 private 实现:ArkTS 不允许子类收窄继承成员的可见性。 新增 docs/canvas-architecture.md、docs/touch-event-architecture.md 记录上述不变量。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
9d08111 to
3cbf926
Compare
目标
这次补齐旧版
wx.createCanvasContext()、Canvas node、小游戏 Canvas 在 Dimina 四端的运行链路,并把 canvas 使用的点击、触摸和label激活语义与微信小程序对齐。最终实现同时覆盖新编译包和已发布旧包,Canvas 的节点归属、绘制顺序、内存边界和 runtime 销毁都由框架层统一管理。Canvas
<canvas>编译为dd-canvas。组件根节点保留布局、id、dataset和事件语义,内部真实 canvas 供 SelectorQuerynode、Canvas 2D / WebGL 和 legacy 回放使用;旧编译包中的原生 canvas 仍可由当前 runtime 解析。canvas-id按页面或自定义组件实例隔离,动态修改canvas-id/type会释放并重新 claim。resolver 不跨组件边界、不选择重复冲突的隐藏节点,也不把 id 拼进 CSS selector。手势与
labeltap、longpress、longtap、canceltap由统一触摸状态机合成,不再把浏览器click直接当作小程序tap。它覆盖位移取消、touchend终点复查、touchcancel、长按抑制、bind/catch传播和动态监听器重装;程序化点击、键盘与无障碍触发仍由click兜底。序列的取消语义按微信实测对齐:位移越过阈值后,之后每一条
touchmove各带一条canceltap;touchmove一条都没到时(被preventDefault吞掉或系统把移动并进抬手),touchend会按起点与终点再判一次距离并改发canceltap,这两条补发路径只在整段序列还没发过canceltap时生效。第二根手指加入只取消长按计时器,longpress/longtap本次序列不再触发,但不影响先落下那根手指的tap。节点卸载时进行中的原生序列仍等真实touchend/touchcancel收口,不伪造终态,但长按计时器立即停表,不给已经离开树的节点补造longpress/longtap。label通过控件登记的激活入口定向激活button、checkbox、input、radio、switch,不再调用target.click()产生第二次tap。容器事件的currentTarget、id和dataset归到实际绑定节点。组件化后 canvas touch 曾因以内层 canvas 为基准产生 4 px 偏移,本次已经修复:触摸点的x/y重新以小程序声明节点的 border box 为坐标原点。兼容与边界
context.reset()时,通过 backing store reset 清理像素、路径、clip、save stack 和绘图状态。tap与canceltap属于这条序列而不是逐个触点;多指同时按下时只有建立序列的那根手指产生终态事件,其余触点只透传原生 touch 事件。glass-easel 按identifier逐触点记账的模型本次不采用,微信公开文档未定义多指下的tap时机。capture-bind/capture-catch与mut-bind仍未实现;本 PR 不扩大到捕获阶段和互斥事件模型。完整设计见 Canvas 运行架构 和 触摸事件与手势。
验证
分支已 rebase 到
main最新的2d7b9ea(HEIF/HEIC 支持),冲突只有harmony/dimina/src/test/List.test.ets和iOS/dimina.xcodeproj/project.pbxproj两处新增用例登记,按并集解决,双方用例都在下面的运行结果里。以下数字是 rebase 之后在3cbf926上重跑的:pnpm lint、production build 和git diff --check通过。diminaTests65 +DiminaKitTests222 = 287 个测试通过,** TEST SUCCEEDED **。hvigorw --mode module -p module=dimina@default test实际执行 hypium 本地单测,21 个测试类、203 个用例通过,0 failure 0 error 0 ignore(entry@default1/1);entryHAP 构建通过。src/ohosTest下目前只有模板用例,未在设备上执行。pnpm generate:sdk从 production dist 重新生成,包内service.js(167,875 B)与pageFrame.js(293,922 B)和 container dist 逐字节一致;JSApp ZIP 完整。