ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ReactOS 图形系统分析(18):路径对象 — PATHOBJ(pathobj.c)

ReactOS 图形系统分析(18):路径对象 — PATHOBJ(pathobj.c) ReactOS 图形系统分析18路径对象 — PATHOBJpathobj.c1. 概述pathobj.c位于win32ss/gdi/eng/pathobj.c实现PATHOBJ路径对象的 DDI 服务函数——即 Windows 图形 DDI 契约中面向显示/打印驱动的路径构建与枚举接口。在 Windows 的 DDI 模型中驱动实现DrvStrokePath/DrvFillPath/DrvStrokeAndFillPath/DrvLineTo时会收到一个PATHOBJ*驱动通过PATHOBJ_bMoveTo/PATHOBJ_bPolyLineTo/PATHOBJ_bEnum等构建或枚举路径。pathobj.c 就是这些服务的实现。┌─────────────────────────────────────────────────────────────┐ │ ntgdi/path.c内核路径记录层Wine 风格 POINTBYTE 数组 │ │ PATH_MoveTo/LineTo/PolyBezier → PATH_AddEntry 累积到 │ │ PATH.pPoints / pFlags 数组 → FillPath/StrokePath 消费 │ ├─────────────────────────────────────────────────────────────┤ │ gdi/eng/pathobj.c本分析对象PATHOBJ DDI 服务 │ │ PATH 对象中并存另一套表示EXTPATHDATA 链表 │ │ ppdFirst/ppdLast/ppdCurrent仅由 PATHOBJ_* 维护 │ │ ├── 生命周期 EngCreatePath / EngDeletePath │ │ ├── 构建 PATHOBJ_bMoveTo / bPolyLineTo / │ │ │ bPolyBezierTo / bCloseFigure │ │ ├── 枚举 PATHOBJ_vEnumStart / bEnum │ │ ├── 查询 PATHOBJ_vGetBounds │ │ └── 未实现 PATHOBJ_vEnumStartClipLines / │ │ PATHOBJ_bEnumClipLines宽线裁剪枚举 │ ├─────────────────────────────────────────────────────────────┤ │ 驱动侧Windows 模型 │ │ DrvStrokePath/DrvFillPath 中调用 PATHOBJ_bEnum 枚举子路径 │ └─────────────────────────────────────────────────────────────┘重要事实与 string.cSTROBJ类似pathobj.c 也是为 DDI 契约预留的服务层——全树含 vga/framebuf 驱动没有任何代码调用PATHOBJ_*/EngCreatePath。EngStrokePath/EngFillPath等入口在 [stubs.c](file:///d:/reactos/win32ss/gdi/eng/stubs.c) 中仍是桩路径的实际描边/填充由 ntgdi 自己完成见第 5 节。2. 核心数据结构2.1 PATHOBJ — DDI 公开路径对象[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L952-L955)typedefstruct_PATHOBJ{FLONG fl;// 路径标志PO_BEZIERS 等ULONG cCurves;// 子路径数量直线段 贝塞尔段计数}PATHOBJ;2.2 PATHDATA — 枚举单元[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L937-L941)typedefstruct_PATHDATA{FLONG flags;// PD_* 标志本段属性ULONG count;// 本段点数POINTFIX*pptfx;// 定点数坐标数组FIX1/64 像素}PATHDATA,*PPATHDATA;PD_标志[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L926-L935)*标志含义PD_BEGINSUBPATH本段是子路径起点PD_ENDSUBPATH本段是子路径终点PD_CLOSEFIGURE子路径闭合终点回到起点且加连接样式PD_BEZIERS本段是贝塞尔曲线每 3 点一组PD_ALL上述全部标志掩码PO_路径标志*PO_BEZIERS含曲线、PO_ELLIPSE、PO_ALL_INTEGERS所有点整数坐标、PO_ENUM_AS_INTEGERS、PO_WIDENED宽化路径。2.3 EPATHOBJ — 引擎扩展路径对象[path.h](file:///d:/reactos/win32ss/gdi/ntgdi/path.h#L61-L66)typedefstruct_EPATHOBJ{PATHOBJ po;// 公开头fl cCurvesPPATH pPath;// 引擎路径对象含 EXTPATHDATA 链表CLIPOBJ*pco;// 关联裁剪对象}EPATHOBJ,*PEPATHOBJ;2.4 PATH — 引擎路径对象[path.h](file:///d:/reactos/win32ss/gdi/ntgdi/path.h#L34-L59)节选关键字段typedefstruct_PATH{BASEOBJECT BaseObject;// GDI 对象头句柄/锁/标志RECTFX rcfxBoundBox;// 包围盒FIXPOINTFX ptfxSubPathStart;// 当前子路径起点FLONG flType;// PATHTYPE_KEEPME / PATHTYPE_STACKPEXTPATHDATA ppdFirst;// ← pathobj.c 维护的链表头PEXTPATHDATA ppdLast;// ← 链表尾FLONG flags;// PATHDATA flagsPEXTPATHDATA ppdCurrent;// ← 枚举游标FLONG fl;// 保存的 PO_* 标志ULONG cCurves;// 线段 贝塞尔计数struct_EPATHOBJ*epo;// 反向指针EngCreatePath 时设置/* ntgdi/path.c 使用的另一套表示Wine 风格 */POINT*pPoints;// 点数组BYTE*pFlags;// 点标志数组intnumEntriesUsed;intnumEntriesAllocated;...}PATH,*PPATH;关键设计PATH 对象里并存两套路径表示——ntgdi 的pPoints/pFlags数组记录用与 pathobj.c 的EXTPATHDATA链表DDI 用二者互不转换、独立维护详见第 5 节。2.5 EXTPATHDATA — 链表节点[path.h](file:///d:/reactos/win32ss/gdi/ntgdi/path.h#L28-L32)typedefstruct_EXTPATHDATA{PATHDATA pd;// 内嵌 DDI PATHDATAflags/count/pptfxstruct_EXTPATHDATA*ppdNext;// 下一段}EXTPATHDATA,*PEXTPATHDATA;3. 函数实现明细3.1 生命周期EngCreatePath / EngDeletePathPATHOBJ*EngCreatePath(VOID){PPATH pPathPATH_AllocPathWithHandle();// 分配带句柄的 PATH GDI 对象pPathObjExAllocatePoolWithTag(PagedPool,sizeof(EPATHOBJ),GDITAG_PATHOBJ);RtlZeroMemory(pPathObj,size);pPathObj-pPathpPath;pPath-flTypePATHTYPE_KEEPME;// 标记路径由 PATHOBJ 保持pPath-epopPathObj;// 双向关联returnpPathObj-po;// 返回公开 PATHOBJ*}EngDeletePath沿ppdFirst链表释放所有EXTPATHDATA节点、释放EPATHOBJ再通过GDIOBJ_vDeleteObject删除 PATH GDI 对象。3.2 构建PATHOBJ_bMoveTo开启新子路径ppd-pd.flagsPD_BEGINSUBPATH;// 标记子路径起点ppd-pd.count1;// 单个点ppd-pd.pptfx[0]ptfx;// 定点坐标if(ppdLast)// 已有子路径 →ppdLast-pd.flags|PD_ENDSUBPATH;// 上一段标记结束ppdLast-ppdNextppd;// 链表追加else// 首个 →ppdFirstppdLastppd;po.cCurves;// 子路径计数 13.3 构建PATHOBJ_bPolyLineTo / PATHOBJ_bPolyBezierTo两者结构对称均按ppdLast 状态三路分发以 PolyLineTo 为例分支条件动作① 无任何子路径ppdLast NULL新建节点PD_BEGINSUBPATH拷贝全部点② 上一段需结束flags (PD_BEZIERS | PD_ENDSUBPATH)新建节点flags0PolyLineTo或PD_BEZIERSPolyBezierTo追加到链表尾③ 可连续拼接其他原地合并重分配count_oldcount_new的点数组拷贝新旧点释放旧数组count cptfx对称性差异设计细节分支②的判定PolyLineTo 为pd.flags (PD_BEZIERS|PD_ENDSUBPATH)PolyBezierTo 为!(pd.flags PD_BEZIERS) || (pd.flags PD_ENDSUBPATH)——即直线段不能混入贝塞尔段反之亦然两种段型各自成段。PolyBezierTo 额外置po.fl | PO_BEZIERS向驱动通告路径含曲线。合并策略分支③避免频繁分配尽量让连续同类线段共享一个 PATHDATA。3.4 闭合PATHOBJ_bCloseFigureppdpPath-ppdLast;// 取最后一段if(ppdNULL)returnFALSE;ppd-pd.flags|PD_CLOSEFIGURE|PD_ENDSUBPATH;// 闭合 结束returnTRUE;3.5 枚举PATHOBJ_vEnumStart / PATHOBJ_bEnumVOIDPATHOBJ_vEnumStart(IN PATHOBJ*ppo){pPathObj-pPath-ppdCurrentpPathObj-pPath-ppdFirst;// 游标复位到头}BOOLPATHOBJ_bEnum(IN PATHOBJ*ppo,OUT PATHDATA*ppd){if(ppdCurrentNULL)returnFALSE;// 枚举结束*ppdppdCurrent-pd;// 返回当前段值拷贝ppdCurrentppdCurrent-ppdNext;// 游标推进return(ppdCurrent!NULL);// 还有更多段}语义一次bEnum返回一段PATHDATA含 flags/count/pptfx 数组驱动据此绘制。游标实现为ppdCurrent指针vEnumStart负责复位——Windows 驱动通常在DrvStrokePath中先vEnumStart再循环bEnum。3.6 查询PATHOBJ_vGetBoundsyTopxLeftMAXLONG;yBottomxRightMINLONG;for(ppdppdFirst;ppd;ppdppdNext)for(i0;ippd-pd.count;i){/* 逐点求 min/max */}if(xLeftxRightyTopyBottom){prectfx-xLeftxLeft;prectfx-yTopyTop;prectfx-xRightxRight1;prectfx-yBottomyBottom1;// 半开区间}else{RtlZeroMemory(prectfx,sizeof(*prectfx));// 空路径 → 零矩形}3.7 未实现PATHOBJ_vEnumStartClipLines / PATHOBJ_bEnumClipLines宽线wide pen描边时的裁剪线条枚举服务。Windows 中DrvStrokePath处理复杂裁剪时GDI 通过vEnumStartClipLines初始化、bEnumClipLines循环返回CLIPLINE记录裁剪后的短线段驱动据此逐段绘制。ReactOS 中两者均为 UNIMPLEMENTED文件头 FIXME 注释也明确标注了这一点。4. 服务导出与调用链PATHOBJ 函数是win32k.sys 导出的 DDI 服务[win32k.spec](file:///d:/reactos/win32ss/win32k.spec#L186-L194)win32k 导出实现状态UMPD 系统调用gdi32→win32uEngCreatePath✓—EngDeletePath✓NtGdiEngDeletePath[umpdstubs](file:///d:/reactos/win32ss/gdi/eng/umpdstubs.c#L224-L232) 桩PATHOBJ_bCloseFigure✓—PATHOBJ_bEnum✓NtGdiPATHOBJ_bEnum桩PATHOBJ_bMoveTo✓—PATHOBJ_bPolyBezierTo✓—PATHOBJ_bPolyLineTo✓—PATHOBJ_vEnumStart✓NtGdiPATHOBJ_vEnumStart桩PATHOBJ_vEnumStartClipLines✗—PATHOBJ_bEnumClipLines✗—PATHOBJ_vGetBounds✓NtGdiPATHOBJ_vGetBounds桩调用关系内核驱动: DrvStrokePath/DrvFillPath 收到 PATHOBJ* ↓ PATHOBJ_bEnum / PATHOBJ_bMoveTo ...直接调 win32k 导出 ↓ eng/pathobj.c本文件 UMPD 驱动: gdi32.PATHOBJ_bEnum → NtGdiPATHOBJ_bEnum → umpdstubs → eng/pathobj.c 仅 4 个函数有 UMPD 路径其余仅内核可用当前状态全代码树含 vga/framebuf没有任何调用者——这些函数仅作为 ABI 导出保留等待EngStrokePath/EngFillPath实现或第三方驱动接入。5. 对照ntgdi/path.c 的实际路径管线ReactOS 当前描边/填充完全由 ntgdi 自己完成不经过 PATHOBJBeginPath → PATH_MoveTo/LineTo/BezierTo → PATH_AddEntry 写入 pPoints/pFlags 数组 ↓ PATH_FillPath → PATH_PathToRegion转区域→ IntGdiFillRgn PATH_StrokePath → 宽笔: PATH_WidenPathEx轮廓化→ 填充 细笔: 逐段 → IntEngLineTo EndPath → NtGdiEndPath → ...两套表示并存于同一PATH对象但互不转换表示维护者用途pPoints/pFlags数组[ntgdi/path.c](file:///d:/reactos/win32ss/gdi/ntgdi/path.c)PATH_AddEntryBeginPath 记录、FillPath/StrokePath 内部消费EXTPATHDATA链表[eng/pathobj.c](file:///d:/reactos/win32ss/gdi/eng/pathobj.c)PATHOBJ_*DDI 服务当前无调用者这与 string.c/STROBJ 的情形完全同构DDI 服务层已实现/预留但引擎的实际渲染路径尚未接线到 DDI 模型。6. 与《分析_4》标注对照标注核对《_4》第 38 行pathobj.c 「路径对象」准确。补充实现主体是 PATHOBJ DDI 服务构建/枚举/查询win32k.spec 导出 9 个符号树内无驱动调用为预留服务层7. 源码索引文件关键内容[pathobj.c](file:///d:/reactos/win32ss/gdi/eng/pathobj.c)EngCreatePath/EngDeletePath、PATHOBJ_bMoveTo/bPolyLineTo/bPolyBezierTo/bCloseFigure/vEnumStart/bEnum/vGetBounds、vEnumStartClipLines/bEnumClipLines桩[path.h](file:///d:/reactos/win32ss/gdi/ntgdi/path.h)PATH / EPATHOBJ / EXTPATHDATA 结构、PATH_* 内部接口[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h)PATHOBJ / PATHDATA 结构、PD_* / PO_* 标志[ntgdi/path.c](file:///d:/reactos/win32ss/gdi/ntgdi/path.c)实际路径记录/描边/填充pPoints/pFlags 数组管线[stubs.c](file:///d:/reactos/win32ss/gdi/eng/stubs.c)EngStrokePath/EngFillPath/EngStrokeAndFillPath 桩[win32k.spec](file:///d:/reactos/win32ss/win32k.spec#L186-L194)PATHOBJ/EngCreatePath 导出[umpdstubs.c](file:///d:/reactos/win32ss/gdi/eng/umpdstubs.c)NtGdiPATHOBJ_*/NtGdiEngDeletePathUMPD 桩关联模块上层记录层[ntgdi/path.c](file:///d:/reactos/win32ss/gdi/ntgdi/path.c)BeginPath/EndPath 系列潜在 DDI 消费者驱动DrvStrokePath/DrvFillPath/DrvStrokeAndFillPathReactOS 树内驱动均未实现相关引擎入口EngStrokePath/EngFillPathstubs.c 桩本文档基于 ReactOS 源代码win32ss/gdi/eng/pathobj.c及关联模块分析2026 年 8 月
返回列表