From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 111 +++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index f4eb2fd9eb0..1c7265c083f 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -173,6 +173,111 @@ static inline void get_bounding_rect(RECT *rect, int x, int y, int width, int he } }
+static inline void order_rect(RECT *rect) +{ + if (rect->left > rect->right) + { + int tmp = rect->left; + rect->left = rect->right; + rect->right = tmp; + } + if (rect->top > rect->bottom) + { + int tmp = rect->top; + rect->top = rect->bottom; + rect->bottom = tmp; + } +} + +BOOL intersect_vis_rectangles(struct bitblt_coords *dst, struct bitblt_coords *src) +{ + RECT rect; + + /* intersect the rectangles */ + + if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */ + { + OffsetRect(&src->visrect, dst->x - src->x, dst->y - src->y); + if (!IntersectRect(&rect, &src->visrect, &dst->visrect)) return FALSE; + src->visrect = dst->visrect = rect; + OffsetRect(&src->visrect, src->x - dst->x, src->y - dst->y); + } + else /* stretching */ + { + /* map source rectangle into destination coordinates */ + rect = src->visrect; + OffsetRect(&rect, + -src->x - (src->width < 0 ? 1 : 0), + -src->y - (src->height < 0 ? 1 : 0)); + rect.left = rect.left * dst->width / src->width; + rect.top = rect.top * dst->height / src->height; + rect.right = rect.right * dst->width / src->width; + rect.bottom = rect.bottom * dst->height / src->height; + order_rect(&rect); + + /* when the source rectangle needs to flip and it doesn't fit in the source device + area, the destination area isn't flipped. So, adjust destination coordinates */ + if (src->width < 0 && dst->width > 0 && + (src->x + src->width + 1 < src->visrect.left || src->x > src->visrect.right)) + dst->x += (dst->width - rect.right) - rect.left; + else if (src->width > 0 && dst->width < 0 && + (src->x < src->visrect.left || src->x + src->width > src->visrect.right)) + dst->x -= rect.right - (dst->width - rect.left); + + if (src->height < 0 && dst->height > 0 && + (src->y + src->height + 1 < src->visrect.top || src->y > src->visrect.bottom)) + dst->y += (dst->height - rect.bottom) - rect.top; + else if (src->height > 0 && dst->height < 0 && + (src->y < src->visrect.top || src->y + src->height > src->visrect.bottom)) + dst->y -= rect.bottom - (dst->height - rect.top); + + OffsetRect(&rect, dst->x, dst->y); + + /* avoid rounding errors */ + rect.left--; + rect.top--; + rect.right++; + rect.bottom++; + if (!IntersectRect(&dst->visrect, &rect, &dst->visrect)) return FALSE; + + /* map destination rectangle back to source coordinates */ + rect = dst->visrect; + OffsetRect(&rect, + -dst->x - (dst->width < 0 ? 1 : 0), + -dst->y - (dst->height < 0 ? 1 : 0)); + rect.left = src->x + rect.left * src->width / dst->width; + rect.top = src->y + rect.top * src->height / dst->height; + rect.right = src->x + rect.right * src->width / dst->width; + rect.bottom = src->y + rect.bottom * src->height / dst->height; + order_rect(&rect); + + /* avoid rounding errors */ + rect.left--; + rect.top--; + rect.right++; + rect.bottom++; + if (!IntersectRect(&src->visrect, &rect, &src->visrect)) return FALSE; + } + return TRUE; +} + +static void clip_visrect(HDC hdc, RECT *dst, const RECT *src) +{ + HRGN hrgn; + + hrgn = CreateRectRgn(0, 0, 0, 0); + if (GetRandomRgn(hdc, hrgn, 3) == 1) + { + GetRgnBox(hrgn, dst); + IntersectRect(dst, dst, src); + } + else + { + *dst = *src; + } + DeleteObject(hrgn); +} + static void get_vis_rectangles(HDC hdc, struct bitblt_coords *dst, const XFORM *xform, DWORD width, DWORD height, struct bitblt_coords *src) { @@ -193,7 +298,7 @@ static void get_vis_rectangles(HDC hdc, struct bitblt_coords *dst, dst->width = -dst->width; } get_bounding_rect(&rect, dst->x, dst->y, dst->width, dst->height); - dst->visrect = rect; + clip_visrect(hdc, &dst->visrect, &rect);
if (!src) return;
@@ -206,8 +311,10 @@ static void get_vis_rectangles(HDC hdc, struct bitblt_coords *dst, src->y = rect.top; src->width = rect.right - rect.left; src->height = rect.bottom - rect.top; - get_bounding_rect( &rect, src->x, src->y, src->width, src->height ); + get_bounding_rect(&rect, src->x, src->y, src->width, src->height); src->visrect = rect; + + intersect_vis_rectangles(dst, src); }
static int stretch_blt(PHYSDEV dev, const EMRSTRETCHBLT *blt,
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 1c7265c083f..620f4153210 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1352,6 +1352,7 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, case EMR_CREATEPEN: case EMR_CREATEBRUSHINDIRECT: case EMR_SETARCDIRECTION: + case EMR_SELECTCLIPPATH: return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); default: FIXME("unsupported record: %ld\n", rec->iType);
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 620f4153210..f1294be48cb 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1353,6 +1353,7 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, case EMR_CREATEBRUSHINDIRECT: case EMR_SETARCDIRECTION: case EMR_SELECTCLIPPATH: + case EMR_EXTSELECTCLIPRGN: return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); default: FIXME("unsupported record: %ld\n", rec->iType);
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/bitmap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/wineps.drv/bitmap.c b/dlls/wineps.drv/bitmap.c index bafc86e9a24..59fbf1c1544 100644 --- a/dlls/wineps.drv/bitmap.c +++ b/dlls/wineps.drv/bitmap.c @@ -197,7 +197,8 @@ DWORD CDECL PSDRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
if (info->bmiHeader.biPlanes != 1) goto update_format; if (info->bmiHeader.biCompression != BI_RGB) goto update_format; - if (info->bmiHeader.biBitCount == 16 || info->bmiHeader.biBitCount == 32) goto update_format; + if (info->bmiHeader.biBitCount != 1 && info->bmiHeader.biBitCount != 4 && + info->bmiHeader.biBitCount != 8 && info->bmiHeader.biBitCount != 24) goto update_format; if (!bits) return ERROR_SUCCESS; /* just querying the format */
TRACE( "bpp %u %s -> %s\n", info->bmiHeader.biBitCount, wine_dbgstr_rect(&src->visrect), @@ -297,7 +298,9 @@ DWORD CDECL PSDRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
update_format: info->bmiHeader.biPlanes = 1; - if (info->bmiHeader.biBitCount > 8) info->bmiHeader.biBitCount = 24; + if (info->bmiHeader.biBitCount != 1 && info->bmiHeader.biBitCount != 4 && + info->bmiHeader.biBitCount != 8 && info->bmiHeader.biBitCount != 24) + info->bmiHeader.biBitCount = 24; info->bmiHeader.biCompression = BI_RGB; return ERROR_BAD_FORMAT; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 133 ++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index f1294be48cb..9382464de8e 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -800,6 +800,132 @@ static int poly_draw(PHYSDEV dev, const POINT *points, const BYTE *types, DWORD return TRUE; }
+static inline void reset_bounds(RECT *bounds) +{ + bounds->left = bounds->top = INT_MAX; + bounds->right = bounds->bottom = INT_MIN; +} + +static BOOL gradient_fill(PHYSDEV dev, const TRIVERTEX *vert_array, DWORD nvert, + const void *grad_array, DWORD ngrad, ULONG mode) +{ + char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + struct bitblt_coords src, dst; + struct gdi_image_bits bits; + HBITMAP bmp, old_bmp; + BOOL ret = FALSE; + TRIVERTEX *pts; + unsigned int i; + HDC hdc_src; + HRGN rgn; + + if (!(pts = malloc(nvert * sizeof(*pts)))) return FALSE; + memcpy(pts, vert_array, sizeof(*pts) * nvert); + for (i = 0; i < nvert; i++) + LPtoDP(dev->hdc, (POINT *)&pts[i], 1); + + /* compute bounding rect of all the rectangles/triangles */ + reset_bounds(&dst.visrect); + for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++) + { + ULONG v = ((ULONG *)grad_array)[i]; + dst.visrect.left = min(dst.visrect.left, pts[v].x); + dst.visrect.top = min(dst.visrect.top, pts[v].y); + dst.visrect.right = max(dst.visrect.right, pts[v].x); + dst.visrect.bottom = max(dst.visrect.bottom, pts[v].y); + } + + dst.x = dst.visrect.left; + dst.y = dst.visrect.top; + dst.width = dst.visrect.right - dst.visrect.left; + dst.height = dst.visrect.bottom - dst.visrect.top; + clip_visrect(dev->hdc, &dst.visrect, &dst.visrect); + + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 24; + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrUsed = 0; + info->bmiHeader.biClrImportant = 0; + info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left; + info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top; + info->bmiHeader.biSizeImage = 0; + memset(&bits, 0, sizeof(bits)); + hdc_src = CreateCompatibleDC(NULL); + if (!hdc_src) + { + free(pts); + return FALSE; + } + bmp = CreateDIBSection(hdc_src, info, DIB_RGB_COLORS, &bits.ptr, NULL, 0); + if (!bmp) + { + DeleteObject(hdc_src); + free(pts); + return FALSE; + } + old_bmp = SelectObject(hdc_src, bmp); + + /* make src and points relative to the bitmap */ + src = dst; + src.x -= dst.visrect.left; + src.y -= dst.visrect.top; + OffsetRect(&src.visrect, -dst.visrect.left, -dst.visrect.top); + for (i = 0; i < nvert; i++) + { + pts[i].x -= dst.visrect.left; + pts[i].y -= dst.visrect.top; + } + ret = GdiGradientFill(hdc_src, pts, nvert, (void *)grad_array, ngrad, mode); + SelectObject(hdc_src, old_bmp); + DeleteObject(hdc_src); + + rgn = CreateRectRgn(0, 0, 0, 0); + if (mode == GRADIENT_FILL_TRIANGLE) + { + const GRADIENT_TRIANGLE *gt = grad_array; + POINT triangle[3]; + HRGN tmp; + + for (i = 0; i < ngrad; i++) + { + triangle[0].x = pts[gt[i].Vertex1].x; + triangle[0].y = pts[gt[i].Vertex1].y; + triangle[1].x = pts[gt[i].Vertex2].x; + triangle[1].y = pts[gt[i].Vertex2].y; + triangle[2].x = pts[gt[i].Vertex3].x; + triangle[2].y = pts[gt[i].Vertex3].y; + tmp = CreatePolygonRgn(triangle, 3, ALTERNATE); + CombineRgn(rgn, rgn, tmp, RGN_OR); + DeleteObject(tmp); + } + } + else + { + const GRADIENT_RECT *gr = grad_array; + HRGN tmp = CreateRectRgn(0, 0, 0, 0); + + for (i = 0; i < ngrad; i++) + { + SetRectRgn(tmp, pts[gr[i].UpperLeft].x, pts[gr[i].UpperLeft].y, + pts[gr[i].LowerRight].x, pts[gr[i].LowerRight].y); + CombineRgn(rgn, rgn, tmp, RGN_OR); + } + DeleteObject(tmp); + } + free(pts); + + OffsetRgn(rgn, dst.visrect.left, dst.visrect.top); + if (ret) + ret = (PSDRV_PutImage(dev, rgn, info, &bits, &src, &dst, SRCCOPY) == ERROR_SUCCESS); + DeleteObject(rgn); + DeleteObject(bmp); + return ret; +} + static HGDIOBJ get_object_handle(struct pp_data *data, HANDLETABLE *handletable, DWORD i, struct brush_pattern **pattern) { @@ -1332,6 +1458,13 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, data->patterns[p->ihBrush].bits.ptr = (BYTE *)p + p->offBits; return 1; } + case EMR_GRADIENTFILL: + { + const EMRGRADIENTFILL *p = (const EMRGRADIENTFILL *)rec; + + return gradient_fill(&data->pdev->dev, p->Ver, p->nVer, + p->Ver + p->nVer, p->nTri, p->ulMode); + }
case EMR_SETWINDOWEXTEX: case EMR_SETWINDOWORGEX:
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 9382464de8e..bab7dfe9773 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -43,6 +43,7 @@ struct pp_data PSDRV_PDEVICE *pdev; DWORD brush; struct brush_pattern *patterns; + BOOL path; };
typedef enum @@ -1183,6 +1184,11 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, return poly_draw(&data->pdev->dev, pts, (BYTE *)(p->aptl + p->cptl), p->cptl) && MoveToEx(data->pdev->dev.hdc, pts[p->cptl - 1].x, pts[p->cptl - 1].y, NULL); } + case EMR_ENDPATH: + { + data->path = FALSE; + return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); + } case EMR_FILLRGN: { const EMRFILLRGN *p = (const EMRFILLRGN *)rec;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index bab7dfe9773..013f019bf8b 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1189,6 +1189,11 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, data->path = FALSE; return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); } + case EMR_ABORTPATH: + { + data->path = FALSE; + return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); + } case EMR_FILLRGN: { const EMRFILLRGN *p = (const EMRFILLRGN *)rec;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 013f019bf8b..e08992dcf01 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -953,11 +953,52 @@ static BOOL fill_rgn(struct pp_data *data, HANDLETABLE *htable, DWORD brush, HRG return ret; }
+static BOOL is_path_record(int type) +{ + switch(type) + { + case EMR_POLYBEZIER: + case EMR_POLYGON: + case EMR_POLYLINE: + case EMR_POLYBEZIERTO: + case EMR_POLYLINETO: + case EMR_POLYPOLYLINE: + case EMR_POLYPOLYGON: + case EMR_MOVETOEX: + case EMR_ANGLEARC: + case EMR_ELLIPSE: + case EMR_RECTANGLE: + case EMR_ROUNDRECT: + case EMR_ARC: + case EMR_CHORD: + case EMR_PIE: + case EMR_LINETO: + case EMR_ARCTO: + case EMR_POLYDRAW: + case EMR_EXTTEXTOUTA: + case EMR_EXTTEXTOUTW: + case EMR_POLYBEZIER16: + case EMR_POLYGON16: + case EMR_POLYLINE16: + case EMR_POLYBEZIERTO16: + case EMR_POLYLINETO16: + case EMR_POLYPOLYLINE16: + case EMR_POLYPOLYGON16: + case EMR_POLYDRAW16: + return TRUE; + default: + return FALSE; + } +} + static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, const ENHMETARECORD *rec, int n, LPARAM arg) { struct pp_data *data = (struct pp_data *)arg;
+ if (data->path && is_path_record(rec->iType)) + return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); + switch (rec->iType) { case EMR_HEADER: @@ -1184,6 +1225,11 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, return poly_draw(&data->pdev->dev, pts, (BYTE *)(p->aptl + p->cptl), p->cptl) && MoveToEx(data->pdev->dev.hdc, pts[p->cptl - 1].x, pts[p->cptl - 1].y, NULL); } + case EMR_BEGINPATH: + { + data->path = TRUE; + return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); + } case EMR_ENDPATH: { data->path = FALSE;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index e08992dcf01..475a0380bbf 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1235,6 +1235,8 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, data->path = FALSE; return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n); } + case EMR_FILLPATH: + return PSDRV_FillPath(&data->pdev->dev); case EMR_ABORTPATH: { data->path = FALSE;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 475a0380bbf..f6481a2b756 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1237,6 +1237,8 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, } case EMR_FILLPATH: return PSDRV_FillPath(&data->pdev->dev); + case EMR_STROKEANDFILLPATH: + return PSDRV_StrokeAndFillPath(&data->pdev->dev); case EMR_ABORTPATH: { data->path = FALSE;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index f6481a2b756..273314325b3 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1239,6 +1239,8 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, return PSDRV_FillPath(&data->pdev->dev); case EMR_STROKEANDFILLPATH: return PSDRV_StrokeAndFillPath(&data->pdev->dev); + case EMR_STROKEPATH: + return PSDRV_StrokePath(&data->pdev->dev); case EMR_ABORTPATH: { data->path = FALSE;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 273314325b3..b5c68f64674 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1548,6 +1548,7 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, case EMR_CREATEPEN: case EMR_CREATEBRUSHINDIRECT: case EMR_SETARCDIRECTION: + case EMR_CLOSEFIGURE: case EMR_SELECTCLIPPATH: case EMR_EXTSELECTCLIPRGN: return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n);
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index b5c68f64674..b0bb17074ab 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1549,6 +1549,7 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, case EMR_CREATEBRUSHINDIRECT: case EMR_SETARCDIRECTION: case EMR_CLOSEFIGURE: + case EMR_FLATTENPATH: case EMR_SELECTCLIPPATH: case EMR_EXTSELECTCLIPRGN: return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n);
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index b0bb17074ab..4bc12783d93 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -1550,6 +1550,7 @@ static int WINAPI hmf_proc(HDC hdc, HANDLETABLE *htable, case EMR_SETARCDIRECTION: case EMR_CLOSEFIGURE: case EMR_FLATTENPATH: + case EMR_WIDENPATH: case EMR_SELECTCLIPPATH: case EMR_EXTSELECTCLIPRGN: return PlayEnhMetaFileRecord(data->pdev->dev.hdc, htable, rec, n);