Improve PAGX SVG export coverage and add shared modifier resolver utilities.#3427
Improve PAGX SVG export coverage and add shared modifier resolver utilities.#3427OnionsYu wants to merge 209 commits into
Conversation
…ile mode instead of stretch mode.
…ect ratio instead of tile mode.
…correct x-y order.
…tch when tileModeX or tileModeY is Repeat or Mirror.
…mage is smaller than the shape.
…mage pattern and shadow code.
…ents and shadows.
…itable vector shapes.
…ration across exporters.
…rove resource management.
…ger cancels overlapping skewed letters.
…ks, modifier edges, and text alignment paths.
…kdrop when rasterizeUnsupported is on.
…ort_svg2 # Conflicts: # src/pagx/ppt/PPTExporter.cpp resolved by feature/onionsyu_export_ppt2 version
…oving the duplicated ApplyStrokeBoxInset definition.
…resolved scales RTL paragraphs and glyph runs.
…on that misuses baselineY as a Y coordinate.
… image bytes when only filePath is set.
…d column so wrapping textAlign End and overflow hidden render correctly.
…t spacing so non-last columns stretch to fill the box like the PAGX renderer.
…PowerPoint uses the real bold face.
…o browsers and CoreText viewers use the real bold face.
…rt_svg2 # Conflicts: # .codebuddy/skills/pagx/references/cli.md # CMakeLists.txt # include/pagx/PPTExporter.h # include/pagx/SVGExporter.h # src/cli/CommandExport.cpp # src/pagx/TextLayout.cpp # src/pagx/TextLayout.h # src/pagx/ppt/PPTExporter.cpp # src/pagx/ppt/PPTFeatureProbe.h # src/pagx/ppt/PPTStyleEmitter.cpp # src/pagx/ppt/PPTTextWriter.cpp # src/pagx/ppt/PPTWriter.h # src/pagx/svg/SVGExporter.cpp # src/pagx/utils/ExporterUtils.cpp # src/pagx/utils/ExporterUtils.h # test/src/PAGXCliTest.cpp # test/src/PAGXPPTTest.cpp
…tting CSS Compositing Level 2 mix-blend-mode values and guarding feBlend against the unsupported Porter-Duff modes.
…ss SVG and PPT exporters to remove mirrored implementations.
…vendored dependency.
…empty shell layers to match verify.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3427 +/- ##
==========================================
+ Coverage 79.69% 80.30% +0.61%
==========================================
Files 580 584 +4
Lines 60823 63580 +2757
Branches 18920 19304 +384
==========================================
+ Hits 48470 51057 +2587
- Misses 8686 8799 +113
- Partials 3667 3724 +57 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
shlzxjp
left a comment
There was a problem hiding this comment.
对 PR 进行了多维度代码评审(架构、API、实现、健壮性、安全、规范、测试),所有发现均经实际代码交叉验证。整体质量较高(注释充分、严守项目禁用项),主要问题集中在共享重构未真正完成、光栅化兜底路径与公开 API 边界保护几处。具体见行级评论。
| @@ -0,0 +1,601 @@ | |||
| ///////////////////////////////////////////////////////////////////////////////////////////////// | |||
There was a problem hiding this comment.
[H1] 共享重构未真正生效:本文件 601 行与 src/pagx/ppt/PPTModifierResolver.cpp diff -u 仅差 28 行(类名 + 2 处注释)。PPTWriter.h:51,703 仍持有 PPTModifierResolver,二进制中并存两份等价实现,PR 标题 "shared modifier resolver utilities" 目标未达成。建议让 PPT 迁移到 pagx::ModifierResolver 并删除 src/pagx/ppt/PPTModifierResolver.{h,cpp},或至少 using PPTModifierResolver = ModifierResolver;。
| canvas->concat(targetLayer->getRelativeMatrix(coordinateSpace)); | ||
| targetLayer->draw(canvas); | ||
| } | ||
| }; |
There was a problem hiding this comment.
[H2] MaskedLayerDrawerInSpace 缺少 scrollRect clip。同文件 826-844 的 MaskedLayerDrawer 注释明示 tgfx::Layer::draw 不应用 layer 自身 scrollRect,必须由 drawer 显式 clipRect。SVGExporter::rasterizeLayerAsImage(SVGExporter.cpp:2077)走此 drawer,且 writeLayer 成功后 return(SVGExporter.cpp:2272)跳过后续 scrollRect 处理。当 layer 同时带 scrollRect 与 unsupported feature(TextPath/TextModifier/Conic/Diamond)时,导出的 <image> 含越界像素。建议在 concat 之后、draw 之前补上对称的 scrollRect clip。
| auto data = GetImageData(image); | ||
| if (data && data->size() > 0) { | ||
| return EncodeImageDataURI(data->bytes(), data->size()); | ||
| } | ||
| return image->filePath; |
There was a problem hiding this comment.
[M1] 加载失败回退为本地绝对路径,与上方注释 "SVG cross-environment usage cannot rely on absolute filesystem paths" 自相矛盾,且会泄露用户机器路径。建议失败时返回 {} 让上层走兜底,避免产出不可移植 SVG。
| return "url(#" + defId + ")"; | ||
| } | ||
| // If baking failed, fall through to try native tiling for Repeat modes | ||
| } |
There was a problem hiding this comment.
[M2] Mirror/Clamp bake 失败时 fall through 到下方 non-tiling 单图分支(行 652),输出"单张图覆盖整 shape",与 Mirror/Clamp 语义不一致。建议 bake 失败且 mode 非 Repeat 时单独处理(保留 native pattern 或显式标错),不要静默落入 Repeat 路径。
| * stretch the denser bitmap over the same visible extent, yielding a crisper result. | ||
| * The default value is 192. | ||
| */ | ||
| int rasterDPI = 192; |
There was a problem hiding this comment.
[M3+L4] rasterDPI 类型 int 且公开 API 文档无合法范围、入口无 clamp。
(1) 0/负数被 pixelWidth<=0 兜住但静默回退到 vector 路径,与 rasterizeUnsupportedFeatures=true 语义矛盾(用户期望保真);
(2) 极端大值在 ExporterUtils.cpp:809 static_cast<int>(std::ceil(width * pixelScale)) 触发 float→int UB(C++ 实现定义)。
对照 HTMLExportOptions::rasterScale 已声明 Valid range: (0, 4]. clamped,建议对齐:API 文档加合法区间,并在 ToSVG/ToFile 入口 clamp 到 [1, 4096] 之类。
| * WebP magic bytes should be detected and produce a data:image/webp URI. | ||
| */ | ||
| PAGX_TEST(PAGXSVGTest, SVGExport_WebpMimeDetection) { | ||
| static constexpr uint8_t kFakeWebp[] = {'R', 'I', 'F', 'F', 0x10, 0x00, 0x00, 0x00, |
There was a problem hiding this comment.
[L1] kFakeWebp 违反规范"不加 k 前缀"。
| private: | ||
| PAGXDocument* _doc; | ||
|
|
||
| // Allocates a new pagx::Path whose data is a fresh PathData owned by _doc. |
There was a problem hiding this comment.
[L2] 私有方法 makePathFromData 上方多行注释违反规范"私有方法不加注释"。如属非显而易见的算法选择,应迁至 .cpp 实现处。同样的问题见 71、75 行(applyTrimToElement、applyRoundCornerToElement)。
| Matrix groupMatrix = BuildGroupMatrix(group); | ||
| Matrix combined = transform * groupMatrix; | ||
| writeTextBoxGroup(out, group, group->elements, combined); | ||
| bool SVGWriter::rasterizeLayerAsImage(SVGBuilder& out, const Layer* layer) { |
There was a problem hiding this comment.
[L3] 函数体内 4 处 return false 静默吞错(layerMap 缺失/!root、!tgfxLayer、!pngData、bounds 空)。建议接入项目日志或对应 [M5] warnings 通道,至少 Debug 构建中输出诊断。
| doc->layers.push_back(layer); | ||
|
|
||
| pagx::SVGExporter::Options opts; | ||
| opts.rasterizeUnsupportedFeatures = false; |
There was a problem hiding this comment.
[T1+T2] 测试覆盖缺口:
(1) 仅此处与 1982 行命中 rasterizeUnsupportedFeatures,且都设为 false。无任何用例验证 rasterizeUnsupportedFeatures=true(默认)路径,即 conic/diamond/TextPath 实际生成 <image> 数据 URI 的端到端断言缺失。
(2) grep "rasterDPI" test/src/ 0 命中,新增 API 字段 rasterDPI(默认 192、边界 0/负/极大)零覆盖。
| * (rather than the legacy SVG 1.1 "tb") is used because text-anchor handling | ||
| * in the legacy keyword path is inconsistent across renderers. | ||
| */ | ||
| PAGX_TEST(PAGXSVGTest, SVGExport_WritingModeVertical) { |
There was a problem hiding this comment.
[T3] WritingModeVertical 仅断言 vertical-rl 字符串。grep "textLength|lengthAdjust" test/src/ 0 命中,新增的 vertical justify 拉伸逻辑(SVGExporter.cpp:1773-1777)未被实测。建议补一个超界文本 + TextAlign::Justify 的 vertical 用例,断言 textLength= 与 lengthAdjust="spacing" 实际写入 SVG。
完善 PAGX 的 SVG 导出能力,并抽取多个导出器共享的辅助模块。
主要变更
不影响 PPT 导出的对外行为,PPTWriter.h 的清理仅为同步共享头的迁移。