[目次] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)
Inside Wine; PHYSDEV
PHYSDEV 型 : struct gdi_physdev へのポインタ
typedef struct gdi_physdev {
const struct gdi_dc_funcs *funcs;
struct gdi_physdev *next;
HDC hdc;
} *PHYSDEV;
WINE は、C言語で書かれていて、C++言語ではないので、継承の概念は無いが、C++の言葉で言えば、事実上、struct gdi_physdev は、
1. X11DRV_PDEVICE
2. struct dibdrv_physdev
3. struct windrv_physdev
の基本クラスと考えられる。それは何故かというと、これら 3つの構造体の先頭のメンバには、全て struct gdi_physdev が埋め込まれているためである。
1. X11DRV_PDEVICE 型 : struct gdi_physdev を継承
/* X physical device */
typedef struct {
struct gdi_physdev dev;
GC gc; /* X Window GC */
Drawable drawable;
RECT dc_rect; /* DC rectangle relative to drawable */
RECT *bounds; /* Graphics bounds */
HRGN region; /* Device region (visible region & clip region) */
X_PHYSPEN pen;
X_PHYSBRUSH brush;
int depth; /* bit depth of the DC */
ColorShifts *color_shifts; /* color shifts of the DC */
int exposures; /* count of graphics exposures operations */
} X11DRV_PDEVICE;
2. struct dibdrv_physdev 型 : struct gdi_physdev を継承
typedef struct dibdrv_physdev {
struct gdi_physdev dev;
dib_info dib;
dib_brush brush;
HRGN clip;
RECT *bounds;
struct cached_font *font;
/* pen */
DWORD pen_style, pen_endcap, pen_join;
BOOL pen_uses_region, pen_is_ext;
int pen_width;
dib_brush pen_brush;
dash_pattern pen_pattern;
dash_pos dash_pos;
rop_mask dash_masks[2];
BOOL (* pen_lines)(struct dibdrv_physdev *pdev, int num, POINT *pts, BOOL close, HRGN region);
} dibdrv_physdev;
3. struct windrv_physdev 型 : struct gdi_physdev を継承
struct windrv_physdev {
struct gdi_physdev dev;
struct dibdrv_physdev *dibdrv;
struct window_surface *surface;
DWORD start_ticks;
};
参考1 : PHYSDEVの登録
static BOOL X11DRV_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
LPCWSTR output, const DEVMODEW* initData ) {
/* 中略 */
X11DRV_PDEVICE *physDev = create_x11_physdev( root_window );
/* 中略 */
push_dc_driver( pdev, &physDev->dev, &x11drv_funcs );
/* 中略 */
}
static BOOL X11DRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev ) {
/* 中略 */
X11DRV_PDEVICE *physDev = create_x11_physdev( stock_bitmap_pixmap );
/* 中略 */
push_dc_driver( pdev, &physDev->dev, &x11drv_funcs );
/* 中略 */
}
// 略さずに完全に掲載 :
static BOOL dibdrv_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
LPCWSTR output, const DEVMODEW *data ) {
dibdrv_physdev *pdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pdev) );
if (!pdev) return FALSE;
clear_dib_info(&pdev->dib);
clear_dib_info(&pdev->brush.dib);
clear_dib_info(&pdev->pen_brush.dib);
push_dc_driver( dev, &pdev->dev, &dib_driver );
return TRUE;
}
// 略さずに完全に掲載 :
static BOOL windrv_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
LPCWSTR output, const DEVMODEW *devmode ) {
struct windrv_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
if (!physdev) return FALSE;
if (!dib_driver.pCreateDC( dev, NULL, NULL, NULL, NULL ))
{
HeapFree( GetProcessHeap(), 0, physdev );
return FALSE;
}
physdev->dibdrv = get_dibdrv_pdev( *dev );
push_dc_driver( dev, &physdev->dev, &window_driver );
return TRUE;
}
// 略さずに完全に掲載 :
void dibdrv_set_window_surface( DC *dc, struct window_surface *surface )
{
char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *info = (BITMAPINFO *)buffer;
RECT rect;
void *bits;
PHYSDEV windev;
struct windrv_physdev *physdev;
struct dibdrv_physdev *dibdrv;
TRACE( "%p %p\n", dc->hSelf, surface );
windev = pop_dc_driver( dc, &window_driver );
if (surface)
{
if (windev) push_dc_driver( &dc->physDev, windev, windev->funcs );
else
{
if (!window_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL )) return;
windev = find_dc_driver( dc, &window_driver );
}
physdev = get_windrv_physdev( windev );
window_surface_add_ref( surface );
if (physdev->surface) window_surface_release( physdev->surface );
physdev->surface = surface;
dibdrv = physdev->dibdrv;
bits = surface->funcs->get_info( surface, info );
init_dib_info_from_bitmapinfo( &dibdrv->dib, info, bits );
/* clip the device rect to the surface */
rect = surface->rect;
offset_rect( &rect, dc->device_rect.left, dc->device_rect.top );
intersect_rect( &dc->device_rect, &dc->device_rect, &rect );
dibdrv->dib.rect = dc->vis_rect;
offset_rect( &dibdrv->dib.rect, -rect.left, -rect.top );
dibdrv->bounds = surface->funcs->get_bounds( surface );
DC_InitDC( dc );
}
else if (windev)
{
dib_driver.pDeleteDC( pop_dc_driver( dc, &dib_driver ));
windev->funcs->pDeleteDC( windev );
DC_InitDC( dc );
}
}
static BOOL pathdrv_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
LPCWSTR output, const DEVMODEW *devmode ) {
/* 中略 */
struct path_physdev *physdev = HeapAlloc( GetProcessHeap(), 0, sizeof(*physdev) );
/* 中略 */
push_dc_driver( dev, &physdev->dev, &path_driver );
/* 中略 */
}
push_dc_driver( dev, &physdev->dev, &freetype_funcs );
push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
push_dc_driver( pdev, &physDev->dev, &macdrv_funcs );
push_dc_driver( pdev, &physDev->dev, &android_drv_funcs );
参考2: PHYSDEVの処理関数セットの色々
static const struct gdi_dc_funcs x11drv_funcs = {・・・};
static const struct gdi_dc_funcs android_drv_funcs = {・・・};
static const struct gdi_dc_funcs macdrv_funcs = {・・・};
static const struct gdi_dc_funcs xrender_funcs = {・・・};
static const struct gdi_dc_funcs psdrv_funcs = {・・・};
const struct gdi_dc_funcs dib_driver = {・・・};
static const struct gdi_dc_funcs window_driver = {・・・};
const struct gdi_dc_funcs *font_driver = NULL;
static const struct gdi_dc_funcs empty_funcs;
const struct gdi_dc_funcs *DRIVER_load_driver( LPCWSTR name ) {・・・}
const struct gdi_dc_funcs null_driver = {・・・};
static const struct gdi_dc_funcs freetype_funcs = {・・・};
static const struct gdi_dc_funcs path_driver = {・・・};
static const struct gdi_dc_funcs emfpath_driver = {・・・};
static const struct gdi_dc_funcs emfdrv_driver = {・・・};
static const struct gdi_dc_funcs MFDRV_driver = {・・・};
struct gdi_physdev の動的型判定(新)
struct gdi_physdev *dev;
の実際のインスタンスの型は何かという話である。それは、結論から言うと、例えば、LineTo() の場合なら、関数ポインタ pLineTo によって、自動的に以下のように処理関数が振り分けられる。
BOOL (*pLineTo)( PHYSDEV dev, INT x, INT y ) :
X11DRV_LineTo // 基本
PSDRV_LineTo // PostScript driver の場合
MFDRV_LineTo // meta file の場合
EMFDRV_LineTo // Enhanced MetaFile driver の場合
dibdrv_LineTo // DIB driver の場合 :
windrv_LineTo // Driver for window surfaces
pathdrv_LineTo // Graphics paths (BeginPath, EndPath etc.) の場合
X11DRV_LineTo(dex, x, y) の中では、dev は、X11DRV_PDEVICE * 型であり、windrv_LineTo(dev, x, y) の中では、dev は、struct windrv_physdev * 型である、ということである。この仕組みで、多くの場合は十分なのではないか。
struct gdi_physdev の動的型判定(旧)
以下の関数で意味的には動的に型を判定できる、しかし、実際には、x11drv_funcs と、window_driver は、static 修飾子を付けて宣言されているので、外部から参照できないため、このままではコンパイルできない。
int __get_type_of_dev( struct gdi_physdev *p_dev )
{
if ( p_dev->funcs == &x11drv_funcs ) {
// p_dev は、X11DRV_PDEVICE * 型である。
return 1;
}
else if ( p_dev->funcs == &dib_driver ) {
// p_dev は、struct dibdrv_physdev * 型である。
return 2;
}
else if ( p_dev->funcs == &window_driver ) {
// p_dev は、struct windrv_physdev * 型である。
return 3;
}
else if (・・・) {・・・}
else if (・・・) {・・・}
・・・
}
&x11drv_funcs については、代わりに、
gdi_dc_funcs *p_x11drv_funcs = X11DRV_get_gdi_driver( WINE_GDI_DRIVER_VERSION );
を用いることが出来る。しかし、window_driver については、参照する方法が無いので、上記の方法は実際には使えない。
const struct gdi_dc_funcs * CDECL X11DRV_get_gdi_driver( unsigned int version )
{
if (version != WINE_GDI_DRIVER_VERSION)
{
ERR( "version mismatch, gdi32 wants %u but winex11 has %u\n", version, WINE_GDI_DRIVER_VERSION );
return NULL;
}
return &x11drv_funcs;
}
PHYSDEV から X11DRV_PDEVICE * を取得する関数
// PHYSDEV が、X11DRV_PDEVICE の基本クラスである場合に限定 :
static inline X11DRV_PDEVICE *get_x11drv_dev( PHYSDEV dev )
{
return (X11DRV_PDEVICE *)dev;
}
// 動的型判定付き :
X11DRV_PDEVICE *__get_x11drv_dev_safe( PHYSDEV dev )
{
if ( dev->funcs == &x11drv_funcs ) {
// dev が X11DRV_PDEVICE 型である時 :
return (X11DRV_PDEVICE *)dev;
}
else {
return NULL;
}
}
PHYSDEV から struct windrv_physdev * を取得する関数
// PHYSDEV が、struct windrv_physdev の基本クラスである場合に限定
static inline struct windrv_physdev *get_windrv_physdev( PHYSDEV dev )
{
return (struct windrv_physdev *)dev;
}
(window_driver は、外部から参照できない。)
// 動的型判定付き :
struct windrv_physdev *__get_windrv_physdev_safe( PHYSDEV dev )
{
if ( dev->funcs == &window_driver ) {
// dev が struct windrv_physdev * 型である時 :
return (struct windrv_physdev *)dev;
}
else {
return NULL;
}
}
HDC から PHYSDEV を取得する方法
[LineTo() の場合の例]
/* WINAPI LintTo() から抜粋 */
DC *dc = get_dc_ptr( hdc );
//update_dc( dc );
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pLineTo );
GET_DC_PHYSDEV() マクロ
GET_DC_PHYSDEV() はマクロなので型は明示的には書かれてない。しかも、funcの型は任意のはず。しかし、書ける部分に限定して書くならば、
PHYSDEV GET_DC_PHYSDEV(DC *dc, func);
となる。マクロの定義は、次のようなもの:
#define GET_DC_PHYSDEV(dc,func) \
get_physdev_entry_point( (dc)->physDev, FIELD_OFFSET(struct gdi_dc_funcs,func))
static inline PHYSDEV get_physdev_entry_point( PHYSDEV dev, size_t offset )
{
while (!((void **)dev->funcs)[offset / sizeof(void *)]) dev = dev->next;
return dev;
}
#define FIELD_OFFSET(type, field) ((LONG)offsetof(type, field))
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ
aaa
あああ