static inline INT get_element_size(const region_element* element) { INT needed = sizeof(DWORD); /* DWORD for the type */ switch(element->type) { case RegionDataRect: return needed + sizeof(GpRect); case RegionDataPath: { const GpPath *path = element->elementdata.path; DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS; /* 3 for headers, once again size doesn't count itself */ needed += sizeof(DWORD) * 3; if (flags & FLAGS_INTPATH) needed += 2 * sizeof(SHORT) * path->pathdata.Count; else needed += 2 * sizeof(FLOAT) * path->pathdata.Count; needed += get_pathtypes_size(path); needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */ return needed; } case RegionDataEmptyRect: case RegionDataInfiniteRect: return needed; default: needed += get_element_size(element->elementdata.combine.left); needed += get_element_size(element->elementdata.combine.right); return needed; } return 0; }
static inline void write_path_types(DWORD* location, INT* offset, const GpPath* path) { memcpy(location + *offset, path->pathdata.Types, path->pathdata.Count); /* The unwritten parts of the DWORD (if any) must be cleared */ if (path->pathdata.Count % sizeof(DWORD)) ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) + path->pathdata.Count, sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD)); *offset += (get_pathtypes_size(path) / sizeof(DWORD)); }
static void write_element(const region_element* element, DWORD *buffer, INT* filled) { write_dword(buffer, filled, element->type); switch (element->type) { case CombineModeReplace: case CombineModeIntersect: case CombineModeUnion: case CombineModeXor: case CombineModeExclude: case CombineModeComplement: write_element(element->elementdata.combine.left, buffer, filled); write_element(element->elementdata.combine.right, buffer, filled); break; case RegionDataRect: write_float(buffer, filled, element->elementdata.rect.X); write_float(buffer, filled, element->elementdata.rect.Y); write_float(buffer, filled, element->elementdata.rect.Width); write_float(buffer, filled, element->elementdata.rect.Height); break; case RegionDataPath: { INT i; const GpPath* path = element->elementdata.path; struct _pathheader { DWORD size; DWORD magic; DWORD count; DWORD flags; } *pathheader; pathheader = (struct _pathheader *)(buffer + *filled); pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS; /* 3 for headers, once again size doesn't count itself */ pathheader->size = sizeof(DWORD) * 3; if (pathheader->flags & FLAGS_INTPATH) pathheader->size += 2 * sizeof(SHORT) * path->pathdata.Count; else pathheader->size += 2 * sizeof(FLOAT) * path->pathdata.Count; pathheader->size += get_pathtypes_size(path); pathheader->magic = VERSION_MAGIC; pathheader->count = path->pathdata.Count; *filled += 4; switch (pathheader->flags & FLAGS_INTPATH) { case FLAGS_NOFLAGS: for (i = 0; i < path->pathdata.Count; i++) { write_float(buffer, filled, path->pathdata.Points[i].X); write_float(buffer, filled, path->pathdata.Points[i].Y); } break; case FLAGS_INTPATH: for (i = 0; i < path->pathdata.Count; i++) { write_packed_point(buffer, filled, &path->pathdata.Points[i]); } break; } write_path_types(buffer, filled, path); break; } case RegionDataEmptyRect: case RegionDataInfiniteRect: break; } }
/***************************************************************************** * GdipCreateRegionPath [GDIPLUS.@] * * Creates a GpRegion from a GpPath * * PARAMS * path [I] path to base the region on * region [O] pointer to the newly allocated region * * RETURNS * SUCCESS: Ok * FAILURE: InvalidParameter * * NOTES * If a path has no floating point points, its points will be stored as shorts * (INTPATH) * * If a path is empty, it is considered to be an INTPATH */ GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region) { region_element* element; GpPoint *pointsi; GpPointF *pointsf; GpStatus stat; DWORD flags = FLAGS_INTPATH; INT count, i; TRACE("%p, %p\n", path, region); if (!(path && region)) return InvalidParameter; *region = GdipAlloc(sizeof(GpRegion)); if(!*region) return OutOfMemory; stat = init_region(*region, RegionDataPath); if (stat != Ok) { GdipDeleteRegion(*region); return stat; } element = &(*region)->node; count = path->pathdata.Count; /* Test to see if the path is an Integer path */ if (count) { pointsi = GdipAlloc(sizeof(GpPoint) * count); pointsf = GdipAlloc(sizeof(GpPointF) * count); if (!(pointsi && pointsf)) { GdipFree(pointsi); GdipFree(pointsf); GdipDeleteRegion(*region); return OutOfMemory; } stat = GdipGetPathPointsI(path, pointsi, count); if (stat != Ok) { GdipDeleteRegion(*region); return stat; } stat = GdipGetPathPoints(path, pointsf, count); if (stat != Ok) { GdipDeleteRegion(*region); return stat; } for (i = 0; i < count; i++) { if (!(pointsi[i].X == pointsf[i].X && pointsi[i].Y == pointsf[i].Y )) { flags = FLAGS_NOFLAGS; break; } } GdipFree(pointsi); GdipFree(pointsf); } stat = GdipClonePath(path, &element->elementdata.pathdata.path); if (stat != Ok) { GdipDeleteRegion(*region); return stat; } /* 3 for headers, once again size doesn't count itself */ element->elementdata.pathdata.pathheader.size = ((sizeof(DWORD) * 3)); switch(flags) { /* Floats, sent out as floats */ case FLAGS_NOFLAGS: element->elementdata.pathdata.pathheader.size += (sizeof(DWORD) * count * 2); break; /* INTs, sent out as packed shorts */ case FLAGS_INTPATH: element->elementdata.pathdata.pathheader.size += (sizeof(DWORD) * count); break; default: FIXME("Unhandled flags (%08x). Expect wrong results.\n", flags); } element->elementdata.pathdata.pathheader.size += get_pathtypes_size(path); element->elementdata.pathdata.pathheader.magic = VERSION_MAGIC; element->elementdata.pathdata.pathheader.count = count; element->elementdata.pathdata.pathheader.flags = flags; (*region)->header.size = sizeheader_size + get_element_size(element); return Ok; }