ReactOS 图形系统分析(19):颜色转换对象 — XLATEOBJ(xlateobj.c/h)
ReactOS 图形系统分析(19):颜色转换对象 — XLATEOBJ(xlateobj.c/h)
1. 概述
xlateobj.c / xlateobj.h位于win32ss/gdi/eng/,实现XLATEOBJ(颜色转换对象)——Windows GDI/DDI 中描述"源表面颜色 → 目标表面颜色"转换的核心对象。它解决一个本质问题:不同位深/格式/调色板的表面之间复制像素时,每个像素值如何映射。
与《分析_16/17/18》不同,xlateobj不是预留服务层,而是引擎最核心、被高频调用的模块:DIB 引擎每个位深(1/4/8/16/24/32bpp)的 BitBlt、拉伸、Alpha 混合、文本字形上屏、画刷填充,全部经过XLATEOBJ_iXlate做像素级颜色转换。
┌─────────────────────────────────────────────────────────────┐ │ 消费方 │ │ DIB 引擎 (dib*.c / BitBlt 内联 XLATEOBJ_iXlate) │ │ eng/bitblt.c (画刷/前景背景色) dib/alphablend.c │ │ dib/stretchblt.c ntgdi(bitblt/fillshap/freetype/palette) │ ├─────────────────────────────────────────────────────────────┤ │ gdi/eng/xlateobj.c(本分析对象) │ │ 核心: EXLATEOBJ 结构 + pfnXlate 函数指针分发 │ │ ├── ~25 个专用转换函数 (FN_XLATE) │ │ ├── EXLATEOBJ_vInitialize: 按源/目标调色板类型选择函数 │ │ └── DDI 公开: XLATEOBJ_iXlate / cGetPalette / │ │ hGetColorTransform / piVector │ ├─────────────────────────────────────────────────────────────┤ │ ntgdi/palette.c (调色板对象/位掩码) │ │ 提供 gpalRGB/gpalRGB555/gpalRGB565/gppalMono 等全局调色板 │ └─────────────────────────────────────────────────────────────┘2. 核心数据结构
2.1 XLATEOBJ — DDI 公开部分([winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L1254-L1261))
typedefstruct_XLATEOBJ{ULONG iUniq;// 唯一编号(每次初始化递增,用于缓存命中判断)FLONG flXlate;// XO_* 标志USHORT iSrcType;// 源调色板类型USHORT iDstType;// 目标调色板类型ULONG cEntries;// 转换表项数ULONG*pulXlate;// 转换表指针(可指向内嵌数组或堆分配)}XLATEOBJ;2.2 EXLATEOBJ — 引擎扩展([xlateobj.h](file:///d:/reactos/win32ss/gdi/eng/xlateobj.h#L19-L51))
typedefstruct_EXLATEOBJ{XLATEOBJ xlo;// 公开头PFN_XLATE pfnXlate;// ← 函数指针分发核心(FASTCALL ULONG(pexlo, iColor))PPALETTE ppalSrc;// 源调色板PPALETTE ppalDst;// 目标调色板PPALETTE ppalDstDc;// 目标 DC 调色板(DC_PALETTE 用)HANDLE hColorTransform;// 颜色变换句柄(ICM)union// 6 个 ULONG 的复用池:{ULONG aulXlate[6];// ① 内嵌小转换表(≤6 项,省去堆分配)struct{// ② 位域转换参数(掩码 + 旋转偏移)ULONG ulRedMask;ULONG ulGreenMask;ULONG ulBlueMask;ULONG ulRedShift;ULONG ulGreenShift;ULONG ulBlueShift;};struct{// ③ 彩色→单色转换参数(点积判别常数)LONG lDeltaR;LONG lDeltaG;LONG lDeltaB;LONG lHalfDist;}ToMono;};}EXLATEOBJ,*PEXLATEOBJ;设计亮点:pfnXlate函数指针 + 6 个 ULONG 的联合池——同一块内嵌存储按转换类型复用作"小表 / 位域掩码偏移 / 单色点积常数",避免为小转换表堆分配,且转换本身是一条快路径调用。
2.3 标志位
XO_转换类型标志([winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L1247-L1249)):*
| 标志 | 含义 |
|---|---|
XO_TRIVIAL | 恒等转换(源值即目标值) |
XO_TABLE | 查表转换 |
XO_TO_MONO | 转换到单色 |
XO_调色板编号(XLATEOBJ_cGetPalette用,[winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h#L3151-L3155)):*XO_SRCPALETTE=1、XO_DESTPALETTE=2、XO_DESTDCPALETTE=3、XO_SRCBITFIELDS=4、XO_DESTBITFIELDS=5。
PAL_调色板类型([palette.h](file:///d:/reactos/win32ss/gdi/ntgdi/palette.h#L10-L28),节选):*
| 标志 | 含义 |
|---|---|
PAL_INDEXED | 索引色(查表,含颜色表) |
PAL_BITFIELDS | 位域(RGB 掩码 + 偏移) |
PAL_RGB/PAL_BGR | 24/32bpp 直接 RGB / BGR 顺序 |
PAL_RGB16_555/PAL_RGB16_565 | 16bpp 高/低 5 位格式 |
PAL_MONOCHROME | 单色(仅 2 色) |
PAL_DIBSECTION | DIB Section 专用(转换方向特殊处理) |
2.4 全局单例 gexloTrivial
EXLATEOBJ gexloTrivial={{0,XO_TRIVIAL,0,0,0,0},EXLATEOBJ_iXlateTrivial};恒等转换的全局实例(flXlate=XO_TRIVIAL+pfnXlate=iXlateTrivial),当无颜色转换需求时直接引用([bitblt_new.c](file:///d:/reactos/win32ss/gdi/eng/bitblt_new.c#L141)、[mouse.c](file:///d:/reactos/win32ss/gdi/eng/mouse.c#L357)),避免每次分配对象。
3. 转换函数族(~25 个 FN_XLATE)
全部签名为FASTCALL ULONG(PEXLATEOBJ, ULONG iColor),按用途分五类:
3.1 单色快速通道
| 函数 | 行为 |
|---|---|
iXlateTrivial | 恒等(返回 iColor) |
iXlateMonoInvert | iColor ^ 1(黑白互换) |
iXlateMonoTo0/iXlateMonoTo1 | 全部映射为 0 / 1 |
iXlateToMono | 查 1 项表:(iColor == pulXlate[0]) |
iXlateRGBToBW/iXlateRGBToWB | 亮度阈值(r+g+b >= 383判黑/白),仅用于纯黑/纯白目标 |
3.2 彩色→单色(点积判别)
EXLATEOBJ_iXlateRGBToMono(pexlo,rgbColor){LONG lDist=r*pexlo->ToMono.lDeltaR+g*pexlo->ToMono.lDeltaG+b*pexlo->ToMono.lDeltaB;return(lDist>pexlo->ToMono.lHalfDist);}把前景/背景色看成 RGB 空间两点,预计算前景减背景的方向向量(lDelta*)与判别阈值(lHalfDist = (|F|²−|B|²)/2),每像素用点积符号判归属——几何意义即"像素点落在前背景连线哪一侧"。iXlateBGRToMono仅是字节序反转版本(GetRValue取蓝)。
3.3 位格式转换(16bpp 家族)
| 转换 | 要点 |
|---|---|
RGBtoBGR/ 反向 | 仅交换 R/B 字节(`(v&0x00ff00ff)<<16 |
RGBto555/BGRto555 | 24bpp → 5-5-5(右移+掩码,含 BGR 序) |
RGBto565/BGRto565 | 24bpp → 5-6-5 |
555toRGB/555toBGR | 5-5-5 → 24bpp,用gajXlate5to8扩位表(5bit→8bit 按 8 间隔扩展) |
565toRGB/565toBGR | 5-6-5 → 24bpp,绿用gajXlate6to8(6bit→8bit,4 间隔) |
555to565/565to555 | 16bpp 互转(复制最高绿位等位操作) |
扩位查表:gajXlate5to8[32]/gajXlate6to8[64]把 5/6 位分量均匀映射到 8 位(如 5bit 值 v →v*255/31取整),比移位+或操作精度更高。
3.4 位域转换
EXLATEOBJ_iXlateShiftAndMask(pexlo,iColor){iNewColor=_rotl(iColor,ulRedShift)&ulRedMask;iNewColor|=_rotl(iColor,ulGreenShift)&ulGreenMask;iNewColor|=_rotl(iColor,ulBlueShift)&ulBlueMask;returniNewColor;}通用位域重排:用循环左移对齐各通道后按掩码提取,源/目标的 555/565/掩码位域一律走此函数。
3.5 调色板索引转换
| 函数 | 行为 |
|---|---|
RGBtoPal/555toPal/565toPal | 转 RGB 后PALETTE_ulGetNearestPaletteIndex求最近色索引 |
BitfieldsToPal | 先 ShiftAndMask 转 RGB 再查最近索引 |
Table | 通用查表:iColor >= cEntries ? 0 : pulXlate[iColor](越界保护) |
4. EXLATEOBJ_vInitialize — 转换器选择器
这是模块的总调度器,根据源/目标调色板类型(flFlags)组合,从 ~25 个函数中挑出最优实现:
关键分支细节:
- MONO→MONO 四情形([xlateobj.c](file:///d:/reactos/win32ss/gdi/eng/xlateobj.c#L541-L589)):先按"DIB/DDB 方向 + 前背景色"算出
iColors[0]/[1],再匹配 4 种简化:(0,1)→Trivial、(1,0)→Invert、(0,0)→To0、(1,1)→To1。 - 彩色→MONO 的 CLR_INVALID 特例:调用方(如
NtGdiSetPixel)传CLR_INVALID表示"直接用 DIB 颜色表做点积判别",此时EXLATEOBJ_vInitRGBToMono用目标单色调色板的 0/1 号色初始化点积参数。 - INDEXED→INDEXED 退化优化:构建全量表后若所有项
pulXlate[i]==i(恒等映射)则释放堆内存、退回 Trivial;表 ≤6 项时直接复用联合池内嵌aulXlate[6],>6才EngAllocMem(GDITAG_PXLATE)。 - 位域偏移预计算
CalculateShift:由源/目标掩码算旋转偏移,使运行时仅_rotl + and。
三个初始化包装:
| 函数 | 用途 |
|---|---|
EXLATEOBJ_vInitXlateFromDCs | 由源/目标 DC 表面调色板初始化(BitBlt 用) |
EXLATEOBJ_vInitXlateFromDCsEx | 同前,但可指定源背景色(透明色/掩码 blt 用) |
EXLATEOBJ_vInitSrcMonoXlate | 强制源为单色调色板(gppalMono,单色源 blt 用) |
EXLATEOBJ_vCleanup:若pulXlate指向堆内存(≠内嵌aulXlate)则EngFreeMem并复位。
5. DDI 公开函数与导出
| 函数 | 行为 | win32k 导出 | UMPD(gdi32→win32u→umpdstubs) |
|---|---|---|---|
XLATEOBJ_iXlate | 转换入口:空指针→原值;否则pfnXlate(pexlo, iColor)分发 | —(内部+UMPD) | NtGdiXLATEOBJ_iXlate([umpdstubs](file:///d:/reactos/win32ss/gdi/eng/umpdstubs.c#L718),桩) |
XLATEOBJ_cGetPalette | 按iPal(XO_* 编号)返回源/目标/DC 调色板颜色(pPalOut==NULL时返回项数);校验PAL_INDEXED/PAL_BITFIELDS匹配 | ✓([win32k.spec](file:///d:/reactos/win32ss/win32k.spec#L228)) | NtGdiXLATEOBJ_cGetPalette(桩) |
XLATEOBJ_hGetColorTransform | 返回 ICM 颜色变换句柄 | ✓(L229) | NtGdiXLATEOBJ_hGetColorTransform(桩) |
XLATEOBJ_piVector | 源为索引色时返回转换表指针,否则 NULL | ✓(L231) | — |
注意:XLATEOBJ_iXlate在 xlateobj.c 中定义前先#undef XLATEOBJ_iXlate(防御早期 winddi.h 曾把它定义成宏);内核态驱动直接调用,用户态 UMPD 经NtGdiXLATEOBJ_iXlate。
6. 消费方与调用链(核心活跃证据)
ntgdi/bitblt.c IntGdiBitBlt → EXLATEOBJ_vInitXlateFromDCs → XLATEOBJ_iXlate(每像素) ↓ BLTINFO.XlateSourceToDest DIB 引擎 (dib1bpp~dib32bpp, stretchblt, alphablend) 内联宏: XLATEOBJ_iXlate(ColorTranslation, Source) ← 每像素调用 eng/bitblt.c 画刷颜色 → XLATEOBJ_iXlate(pxloBrush, iSolidColor) 前/背景色 → pxloRGB2Dest ntgdi/freetype.c 文本 → exloRGB2Dst / exloDst2RGB (字形掩码与画刷) ntgdi/fillshap.c 椭圆/洪水填充 → 目标色转换 ntgdi/dcutil.c GetPixel/SetPixel → gpalRGB → 表面调色板 ntgdi/palette.c GetNearestColor → EXLATEOBJ_vInitialize + iXlate ntgdi/dibobj.c DIB 位图/调色板互转 dib/alphablend.c Alpha 混合 → 3 个 exlo 来回转换/* DIB 引擎内联转换宏(dib.h),所有位深 BitBlt 的像素必经之路 */#defineXLATEOBJ_iXlate(ColorTranslation,Source)\((ColorTranslation)?\XLATEOBJ_pfnXlate(ColorTranslation)((ColorTranslation),(Source)):(Source))性能设计:转换以函数指针单跳实现(无分支判断);Trivial 情形(最普遍,如 32bpp→32bpp 同格式)退化为直接返回原值,DIB 引擎甚至可走无转换快路径。
7. 与《分析_4》标注对照
| 标注 | 核对 |
|---|---|
| 《_4》第 39 行:xlateobj.c/h =「颜色转换对象」 | 准确。补充:核心活跃模块(非预留层);由 EXLATEOBJ.pfnXlate 函数指针分发 ~25 个专用转换函数,EXLATEOBJ_vInitialize 按调色板类型选择实现 |
8. 源码索引
| 文件 | 关键内容 |
|---|---|
| [xlateobj.c](file:///d:/reactos/win32ss/gdi/eng/xlateobj.c) | 转换函数族、EXLATEOBJ_vInitialize/vInitXlateFromDCs(Ex)/vInitSrcMonoXlate/vCleanup、XLATEOBJ_iXlate/cGetPalette/hGetColorTransform/piVector |
| [xlateobj.h](file:///d:/reactos/win32ss/gdi/eng/xlateobj.h) | EXLATEOBJ 结构(联合池)、PFN_XLATE、初始化声明 |
| [winddi.h](file:///d:/reactos/sdk/include/psdk/winddi.h) | XLATEOBJ 结构、XO_* 标志、ENGAPI 声明 |
| [palette.h](file:///d:/reactos/win32ss/gdi/ntgdi/palette.h) | PAL_* 标志、CalculateShift、gpalRGB 等全局 |
| [palette.c](file:///d:/reactos/win32ss/gdi/ntgdi/palette.c) | 调色板对象、全局调色板初始化 |
| [dib.h](file:///d:/reactos/win32ss/gdi/dib/dib.h) | XLATEOBJ_iXlate 内联宏(BLTINFO 中调用) |
| [bitblt.c](file:///d:/reactos/win32ss/gdi/eng/bitblt.c) | 画刷/前景背景色转换消费 |
| [ntgdi/bitblt.c](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c) | IntGdiBitBlt 初始化 exlo |
| [umpdstubs.c](file:///d:/reactos/win32ss/gdi/eng/umpdstubs.c#L705-L740) | NtGdiXLATEOBJ_*(UMPD 桩) |
关联模块:
- 上层调用者:[ntgdi/](file:///d:/reactos/win32ss/gdi/ntgdi/bitblt.c)(BitBlt/GetPixel/填充/文本)
- 后端消费:[gdi/dib/](file:///d:/reactos/win32ss/gdi/dib/)(各位深 BitBlt 内联转换)
- 调色板来源:[ntgdi/palette.c](file:///d:/reactos/win32ss/gdi/ntgdi/palette.c)
- 兄弟对象:BRUSHOBJ/CLIPOBJ/SURFOBJ(同属 DDI 对象族)
本文档基于 ReactOS 源代码
win32ss/gdi/eng/xlateobj.c/h及关联模块分析(2026 年 8 月)
