Inside Wine; PHYSDEV

[目次] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)

# Inside Wine; PHYSDEV


## PHYSDEV 型 : struct gdi_physdev へのポインタ

```c:~/wine/include/wine/gdi_driver.h
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 を継承

```c:~/wine/dlls/winex11.drv/x11drv.h
/* 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 を継承

```c:~/wine/dlls/gdi32/dibdrv/dibdrv.h
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 を継承

```c:~/wine/dlls/gdi32/dibdrv/dc.c
struct windrv_physdev {
    struct gdi_physdev     dev;
    struct dibdrv_physdev *dibdrv;
    struct window_surface *surface;
    DWORD                  start_ticks;
};
```



## 参考1 : PHYSDEVの登録

```c:~/wine/dlls/winex11.drv/init.c
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 );
	/* 中略 */
}
```

```c:~/wine/dlls/gdi32/dibdrv/dc.c
// 略さずに完全に掲載 :
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 );
	}
}
```

```c:~/wine/dlls/gdi32/path.c
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 );
	/* 中略 */
}
```

```c:~/wine/dlls/gdi32/freetype.c
push_dc_driver( dev, &physdev->dev, &freetype_funcs );
```

```c:~/wine/dlls/wineeps.drv/init.c
push_dc_driver( pdev, &physDev->dev, &psdrv_funcs );
```

```c:~/wine/dlls/winemac.drv/gdi.c
push_dc_driver( pdev, &physDev->dev, &macdrv_funcs );
```

```c:~/wine/dlls/wineandroid.drv/init.c
push_dc_driver( pdev, &physDev->dev, &android_drv_funcs );
```

## 参考2: PHYSDEVの処理関数セットの色々

```c:~/wine/dlls/winex11.drv/init.c
static const struct gdi_dc_funcs x11drv_funcs = {・・・};
```

```c:~/wine/dlls/wineandroid.drv/init.c
static const struct gdi_dc_funcs android_drv_funcs = {・・・};
```

```c:~/wine/dlls/winemac.drv/init.c
static const struct gdi_dc_funcs macdrv_funcs = {・・・};
```

```c:~/wine/dlls/winex11.drv/xrender.c
static const struct gdi_dc_funcs xrender_funcs = {・・・};
```

```c:~/wine/dlls/wineeps.drv/init.c
static const struct gdi_dc_funcs psdrv_funcs = {・・・};
```

```c:~/wine/dlls/gdi32/dibdrv/dc.c
const struct gdi_dc_funcs dib_driver = {・・・};
static const struct gdi_dc_funcs window_driver = {・・・};
```

```c:~/wine/dlls/gdi32/driver.c
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 = {・・・};
```

```c:~/wine/dlls/gdi32/freetype.c
static const struct gdi_dc_funcs freetype_funcs = {・・・};
```

```c:~/wine/dlls/gdi32/path.c
static const struct gdi_dc_funcs path_driver = {・・・};
```

```c:~/wine/dlls/gdi32/enhmfdrv/dc.c
static const struct gdi_dc_funcs emfpath_driver = {・・・};
```

```c:~/wine/dlls/gdi32/enhmfdrv/init.c
static const struct gdi_dc_funcs emfdrv_driver = {・・・};
```

```c:~/wine/dlls/gdi32/mfdrv/init.c
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 修飾子を付けて宣言されているので、外部から参照できないため、このままではコンパイルできない。

```c:擬似関数
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 については、代わりに、

```c:
gdi_dc_funcs	*p_x11drv_funcs	= X11DRV_get_gdi_driver( WINE_GDI_DRIVER_VERSION );
```

を用いることが出来る。しかし、window_driver については、参照する方法が無いので、上記の方法は実際には使えない。


```c:~/wine/dlls/winex11.drv/init.c
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 * を取得する関数


   
```c:~/wine/dlls/winex11.drv/x11drv.h
// PHYSDEV が、X11DRV_PDEVICE の基本クラスである場合に限定 :
static inline X11DRV_PDEVICE *get_x11drv_dev( PHYSDEV dev )
{
    return (X11DRV_PDEVICE *)dev;
}
```

```c:独自関数
// 動的型判定付き :
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 * を取得する関数


```c:~/wine/dlls/gdi32/dibdev/dc.c
// PHYSDEV が、struct windrv_physdev の基本クラスである場合に限定
static inline struct windrv_physdev *get_windrv_physdev( PHYSDEV dev )
{
    return (struct windrv_physdev *)dev;
}
```

(window_driver は、外部から参照できない。)

```c:独自関数
// 動的型判定付き :
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() の場合の例]

```c:~/wine/dlls/gdi32/painting.c
/* 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の型は任意のはず。しかし、書ける部分に限定して書くならば、

```c:
PHYSDEV GET_DC_PHYSDEV(DC *dc, func);
```

となる。マクロの定義は、次のようなもの：

```c:~/wine/dlls/gdi32/gdi_private.h
#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;
}
```

```c:~/wine/include/winnt.h
#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

あああ



## end