static void DrawPolyPolyPolygonRaw( SystemDraw& draw, const Point *vertices, int vertex_count, const int *subpolygon_counts, int subpolygon_count_count, const int *disjunct_polygon_counts, int disjunct_polygon_count_count) { GuiLock __; for(int i = 0; i < disjunct_polygon_count_count; i++, disjunct_polygon_counts++) { int poly = *disjunct_polygon_counts; int sub = 1; if(*subpolygon_counts < poly) if(disjunct_polygon_count_count > 1) { const int *se = subpolygon_counts; int total = 0; while(total < poly) total += *se++; sub = (int)(se - subpolygon_counts); } else sub = subpolygon_count_count; ASSERT(sizeof(POINT) == sizeof(Point)); // modify algorithm when not if(sub == 1) Polygon(draw, (const POINT *)vertices, poly); else PolyPolygon(draw, (const POINT *)vertices, subpolygon_counts, sub); vertices += poly; subpolygon_counts += sub; } }
static void DrawPolyPolygonRaw(Draw& draw, const Point *vertices, int vertex_count, const int *subpolygon_counts, int subpolygon_count_count, bool is_inside, int outline_width, Color outline_color ) { #ifdef SYSTEMDRAW SystemDraw *w = dynamic_cast<SystemDraw *>(&draw); if(w) { SystemDraw& draw = *w; #endif draw.SetDrawPen(outline_width, outline_color); ASSERT(sizeof(POINT) == sizeof(Point)); // modify algorithm when not enum { MAX_POLY = 8000 }; if(subpolygon_count_count == 1 && vertex_count < MAX_POLY) Polygon(draw, (const POINT *)vertices, vertex_count); else if(vertex_count < MAX_POLY) PolyPolygon(draw, (const POINT *)vertices, subpolygon_counts, subpolygon_count_count); else { if(is_inside) { draw.SetDrawPen(PEN_NULL, Black); Vector<Point> split_vertices; Vector<int> split_counts; #ifdef SYSTEMDRAW SplitPolygon(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, split_vertices, split_counts, Size(9999, 9999)); #else SplitPolygon(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, split_vertices, split_counts, draw.GetClip()); #endif //!! todo: maxcount for splitpolygon const Point *sv = split_vertices.Begin(); for(const int *sc = split_counts.Begin(), *se = split_counts.End(); sc < se; sc++) { Polygon(draw, (const POINT *)sv, *sc); sv += *sc; } } if(outline_width != PEN_NULL) { draw.DrawPolyPolyline(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, outline_width, outline_color, Null); Buffer<Point> finish(2 * subpolygon_count_count); Buffer<int> counts(subpolygon_count_count); Fill(&counts[0], &counts[subpolygon_count_count], 2); Point *d = finish; const Point *p = vertices; const int *c = subpolygon_counts, *e = c + subpolygon_count_count; while(c < e) { *d++ = *p; *d++ = (p += *c++)[-1]; } draw.DrawPolyPolyline(finish, 2 * subpolygon_count_count, counts, subpolygon_count_count, outline_width, outline_color, Null); } draw.SetDrawPen(outline_width, outline_color); } #ifdef SYSTEMDRAW } #endif }
void DrawPolyPolyPolygon(Draw& draw, const Point *vertices, int vertex_count, const int *subpolygon_counts, int subpolygon_count_count, const int *disjunct_polygon_counts, int disjunct_polygon_count_count, Color color, int width, Color outline, uint64 pattern, Color doxor) { if(vertex_count == 0) return; #ifdef PLATFORM_WIN32_ //!!TODO if(PdfDraw *pdf = dynamic_cast<PdfDraw *>(&draw)) { pdf->DrawPolyPolyPolygon(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, disjunct_polygon_counts, disjunct_polygon_count_count, color, width, outline, pattern, doxor); return; } #endif // LOG("DrawPolyPolyPolygon: drawing = " << (draw.IsDrawing() ? "yes" : "no") // << ", backdraw = " << (draw.IsBack() ? "yes" : "no") // << ", " << (draw.Dots() ? "dots" : "pixels") // << ", printer = " << (draw.IsPrinter() ? "yes" : "no")); // LOG("#vertices = " << vertex_count << ", #subpolygons = " << subpolygon_count_count // << ", #disjunct polygons = " << disjunct_polygon_count_count); // LOG("color = " << Dump(color) << ", width = " << width << ", outline = " << Dump(outline) // << ", pattern = " << Dump(pattern) << ", doxor = " << doxor); #ifdef _DEBUG // for(int v = 0; v < vertex_count; v++) // if(abs2(vertices[v] - vertices[(v ? v : vertex_count) - 1]) >= 500 * 500) // NEVER(); #endif if(!dynamic_cast<SystemDraw *>(&draw)) { draw.DrawPolyPolyPolygon(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, disjunct_polygon_counts, disjunct_polygon_count_count, color, width, outline, pattern, doxor); return; } // TIMING("DrawPolyPolygon/hdc"); bool is_xor = !IsNull(doxor); #ifdef PLATFORM_X11 unsigned xor_pixel = (is_xor ? GetXPixel(doxor) : 0); XGCValues gcv; gcv.function = is_xor ? X11_ROP2_XOR : X11_ROP2_COPY; GC fill_gc = NULL; Image pattern_image; if(!IsNull(color)) { gcv.foreground = GetXPixel(color) ^ xor_pixel; int fmask = GCForeground | GCFunction; if(pattern) { pattern_image = GetPatternImage(pattern); gcv.stipple = pattern_image.GetMaskPixmap(); gcv.fill_style = FillStippled; fmask |= GCStipple | GCFillStyle; } fill_gc = XCreateGC(Xdisplay, draw.GetDrawable(), fmask, &gcv); } GC line_gc = NULL; if(!IsNull(outline)) { gcv.foreground = GetXPixel(outline) ^ xor_pixel; gcv.line_width = width; line_gc = XCreateGC(Xdisplay, draw.GetDrawable(), GCForeground | GCFunction | GCLineWidth, &gcv); Point offset = draw.GetOffset(); } #endif for(int i = 0; i < disjunct_polygon_count_count; i++, disjunct_polygon_counts++) { int poly = *disjunct_polygon_counts; int sub = 1; if(*subpolygon_counts < poly) if(disjunct_polygon_count_count > 1) { const int *se = subpolygon_counts; int total = 0; while(total < poly) total += *se++; sub = se - subpolygon_counts; } else sub = subpolygon_count_count; if(sub > poly) { vertices += poly; subpolygon_counts += sub; continue; } #if defined(PLATFORM_WIN32) #ifdef SYSTEMDRAW SystemDraw *w = dynamic_cast<SystemDraw *>(&draw); if(w) { SystemDraw& draw = *w; #endif if(pattern) { int old_rop = GetROP2(draw); HGDIOBJ old_brush = GetCurrentObject(draw, OBJ_BRUSH); word wpat[8] = { (byte)(pattern >> 56), (byte)(pattern >> 48), (byte)(pattern >> 40), (byte)(pattern >> 32), (byte)(pattern >> 24), (byte)(pattern >> 16), (byte)(pattern >> 8), (byte)(pattern >> 0), }; HBITMAP bitmap = CreateBitmap(8, 8, 1, 1, wpat); HBRUSH brush = ::CreatePatternBrush(bitmap); COLORREF old_bk = GetBkColor(draw); COLORREF old_fg = GetTextColor(draw); if(!is_xor) { SetROP2(draw, R2_MASKPEN); SelectObject(draw, brush); SetTextColor(draw, Black()); SetBkColor(draw, White()); DrawPolyPolygonRaw(draw, vertices, poly, subpolygon_counts, sub, true, PEN_NULL, Null); SetROP2(draw, R2_MERGEPEN); SetTextColor(draw, color); SetBkColor(draw, Black()); } else { // xor fill with pattern data SetROP2(draw, R2_XORPEN); SelectObject(draw, brush); } DrawPolyPolygonRaw(draw, vertices, poly, subpolygon_counts, sub, true, PEN_NULL, Null); SelectObject(draw, old_brush); SetTextColor(draw, old_fg); SetBkColor(draw, old_bk); SetROP2(draw, old_rop); DeleteObject(brush); DeleteObject(bitmap); if(!IsNull(outline)) { draw.SetColor(Null); draw.SetDrawPen(width, outline); ASSERT(sizeof(POINT) == sizeof(Point)); PolyPolygon(draw, (const POINT *)vertices, subpolygon_counts, sub); } } else { // simple fill // RTIMING("AreaTool::Fill(solid color)"); int out_wd = (IsNull(width) || IsNull(outline) ? PEN_NULL : width); Color out_co = Nvl(outline, Black); draw.SetDrawPen(out_wd, out_co); if(is_xor) { color = Color(color.GetR() ^ doxor.GetR(), color.GetG() ^ doxor.GetG(), color.GetB() ^ doxor.GetB()); SetROP2(draw, R2_XORPEN); } HGDIOBJ old_brush = 0; if(IsNull(color)) { static HGDIOBJ null_brush = GetStockObject(NULL_BRUSH); old_brush = SelectObject(draw, null_brush); } else draw.SetColor(color); DrawPolyPolygonRaw(draw, vertices, poly, subpolygon_counts, sub, !IsNull(color), out_wd, out_co); if(old_brush) SelectObject(draw, old_brush); if(is_xor) SetROP2(draw, R2_COPYPEN); } #ifdef SYSTEMDRAW } #endif #elif defined(PLATFORM_X11) if(fill_gc) FillPolyPolygonRaw(fill_gc, draw.GetDrawable(), draw.GetClip(), draw.GetOffset(), vertices, poly, subpolygon_counts, sub); if(line_gc) DrawPolyPolygonRaw(line_gc, draw.GetDrawable(), draw.GetOffset(), vertices, poly, subpolygon_counts, sub); #else #error #endif vertices += poly; subpolygon_counts += sub; }
GpStatus gdip_metafile_play_wmf (MetafilePlayContext *context) { GpStatus status = Ok; GpMetafile *metafile = context->metafile; BYTE *data = metafile->data; BYTE *end = data + metafile->length; #ifdef DEBUG_WMF int i = 1, j; #endif /* reality check - each record is, at minimum, 6 bytes long (4 size + 2 function) */ while (data < end - WMF_MIN_RECORD_SIZE) { DWORD size = GETDW(RECORDSIZE); WORD func = GETW(FUNCTION); int params = size - (WMF_MIN_RECORD_SIZE / sizeof (WORD)); #ifdef DEBUG_WMF printf ("\n[#%d] size %d ", i++, size); #endif /* reality check - enough data available to read all parameters ? (params is in WORD) */ if ((params << 1) > (long)(end - data)) { status = InvalidParameter; goto cleanup; } /* Notes: * - The previous check doesn't mean we have all required parameters (only the one encoded) * - sometimes there are extra (undocumented?, buggy?) parameters for some functions */ switch (func) { case META_SAVEDC: WMF_CHECK_PARAMS(0); status = gdip_metafile_SaveDC (context); break; case META_SETBKMODE: WMF_CHECK_PARAMS(1); status = gdip_metafile_SetBkMode (context, GETW(WP1)); break; case META_SETMAPMODE: WMF_CHECK_PARAMS(1); status = gdip_metafile_SetMapMode (context, GETW(WP1)); break; case META_SETROP2: WMF_CHECK_PARAMS(1); status = gdip_metafile_SetROP2 (context, GETW(WP1)); break; case META_SETRELABS: WMF_CHECK_PARAMS(1); status = gdip_metafile_SetRelabs (context, GETW(WP1)); break; case META_SETPOLYFILLMODE: WMF_CHECK_PARAMS(1); status = gdip_metafile_SetPolyFillMode (context, GETW(WP1)); break; case META_SETSTRETCHBLTMODE: WMF_CHECK_PARAMS(1); /* 2 but second is unused (32bits?) */ status = gdip_metafile_SetStretchBltMode (context, GETW(WP1)); break; case META_RESTOREDC: WMF_CHECK_PARAMS(0); status = gdip_metafile_RestoreDC (context); break; case META_SELECTOBJECT: WMF_CHECK_PARAMS(1); status = gdip_metafile_SelectObject (context, GETW(WP1)); break; case META_SETTEXTALIGN: WMF_CHECK_PARAMS(1); status = gdip_metafile_SetTextAlign (context, GETW(WP1)); break; case META_DELETEOBJECT: WMF_CHECK_PARAMS(1); status = gdip_metafile_DeleteObject (context, GETW(WP1)); break; case META_SETBKCOLOR: WMF_CHECK_PARAMS(2); status = gdip_metafile_SetBkColor (context, GetColor (GETW(WP1), GETW(WP2))); break; case META_SETWINDOWORG: WMF_CHECK_PARAMS(2); status = gdip_metafile_SetWindowOrg (context, GETS(WP1), GETS(WP2)); break; case META_SETWINDOWEXT: WMF_CHECK_PARAMS(2); status = gdip_metafile_SetWindowExt (context, GETS(WP1), GETS(WP2)); break; case META_LINETO: WMF_CHECK_PARAMS(2); status = gdip_metafile_LineTo (context, GETS(WP1), GETS(WP2)); break; case META_MOVETO: WMF_CHECK_PARAMS(2); status = gdip_metafile_MoveTo (context, GETS(WP1), GETS(WP2)); break; case META_CREATEPENINDIRECT: /* note: documented with only 4 parameters, LOGPEN use a POINT to specify width, so y (3) is unused) */ WMF_CHECK_PARAMS(5); status = gdip_metafile_CreatePenIndirect (context, GETW(WP1), GETW(WP2), GetColor (GETW(WP4), GETW(WP5))); break; case META_CREATEBRUSHINDIRECT: WMF_CHECK_PARAMS(4); status = gdip_metafile_CreateBrushIndirect (context, GETW(WP1), GetColor (GETW(WP2), GETW(WP3)), GETW(WP4)); break; case META_POLYGON: status = Polygon (context, data, params); break; case META_POLYLINE: status = Polyline (context, data); break; case META_POLYPOLYGON: status = PolyPolygon (context, data); break; case META_ARC: WMF_CHECK_PARAMS(8); status = gdip_metafile_Arc (context, GETS(WP1), GETS(WP2), GETS(WP3), GETS(WP4), GETS(WP5), GETS(WP6), GETS(WP7), GETS(WP8)); break; case META_RECTANGLE: WMF_CHECK_PARAMS (4); status = gdip_metafile_Rectangle (context, GETS (WP1), GETS (WP2), GETS (WP3), GETS (WP4)); break; case META_SETPIXEL: WMF_CHECK_PARAMS (4); status = gdip_metafile_SetPixel (context, GetColor (GETW (WP1), GETW (WP2)), GETW (WP4), GETW (WP3)); break; case META_STRETCHDIB: { WMF_CHECK_PARAMS(14); BITMAPINFO *bmi = (BITMAPINFO*) (data + 14 * sizeof (WORD)); void* bits = (void*) (bmi + GETDW(WP12)); status = gdip_metafile_StretchDIBits (context, GETS(WP11), GETS(WP10), GETS(WP9), GETS(WP8), GETS(WP7), GETS(WP6), GETS(WP5), GETS(WP4), bits, bmi, GETW(WP3), GETDW(WP1)); break; } case META_DIBSTRETCHBLT: { WMF_CHECK_PARAMS(12); BITMAPINFO *bmi = (BITMAPINFO*) (data + 13 * sizeof (WORD)); void* bits = (void*) (bmi + GETDW(WP11)); status = gdip_metafile_StretchDIBits (context, GETS(WP10), GETS(WP9), GETS(WP8), GETS(WP7), GETS(WP6), GETS(WP5), GETS(WP4), GETS(WP3), bits, bmi, 0, GETDW(WP1)); break; } default: /* unprocessed records, ignore the data */ /* 3 for size (DWORD) == 2 * SHORT + function == 1 SHORT */ #ifdef DEBUG_WMF printf ("Unimplemented_%X (", func); for (j = 0; j < params; j++) { printf (" %d", GetParam (j, data)); } printf (" )"); #endif break; } if (status != Ok) { g_warning ("Parsing interupted, status %d returned from function %d.", status, func); goto cleanup; } data += size * 2; } cleanup: return status; }
// A carbon copy of the Win\Gdi\Region\Polygon implementation // without some parameter checks (no poly-fill-mode given) PHP_METHOD(WinGdiRegionPolygon, polygon) { wingdi_devicecontext_object *dc_obj; wingdi_path_object *path_obj; HashPointer p; // We use this to determine what index we are at in the array POINT *points = NULL; zval ***parameters, **current_elem, **x, **y; INT *point_counts = NULL; // Number of POINTs in corresponding points array int ints_in_count = 0, // Number of ints in point_counts param_count, i, t = 0; // Total number of POINTs WINGDI_ERROR_HANDLING(); // Will throw an exception if no parameters are given if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", ¶meters, ¶m_count) == FAILURE) return; WINGDI_RESTORE_ERRORS(); point_counts = emalloc(param_count * sizeof(INT)); for (i = 0; i < param_count; i++) { if (Z_TYPE_PP(parameters[i]) == IS_ARRAY) { point_counts[ints_in_count] = 0; for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(parameters[i])); zend_hash_has_more_elements(Z_ARRVAL_PP(parameters[i])) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_PP(parameters[i]))) { points = erealloc(points, t * sizeof(POINT) + sizeof(POINT)); zend_hash_get_pointer(Z_ARRVAL_PP(parameters[i]), &p); zend_hash_get_current_data(Z_ARRVAL_PP(parameters[i]), (void **)¤t_elem); if (Z_TYPE_PP(current_elem) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "expected array in array for parameter %d, got %s", i + 1, zend_zval_type_name(*current_elem)); goto CLEANUP; } else { if (zend_hash_num_elements(Z_ARRVAL_PP(current_elem)) != 2) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "expected point-array at index %d for parameter %d to have 2 elements, %d given", p.h, i + 1, zend_hash_num_elements(Z_ARRVAL_PP(current_elem))); goto CLEANUP; } else { zend_hash_index_find(Z_ARRVAL_PP(current_elem), 0, (void **)&x); zend_hash_index_find(Z_ARRVAL_PP(current_elem), 1, (void **)&y); if (Z_TYPE_PP(x) != IS_LONG) convert_to_long(*x); if (Z_TYPE_PP(y) != IS_LONG) convert_to_long(*y); points[t].x = Z_LVAL_PP(x); points[t].y = Z_LVAL_PP(y); t++; point_counts[ints_in_count]++; } } } ints_in_count++; } else { php_error_docref(NULL TSRMLS_CC, E_ERROR, "expecting array for parameter %d, got %s", zend_zval_type_name(*(parameters[i]))); goto CLEANUP; } } path_obj = zend_object_store_get_object(getThis() TSRMLS_CC); dc_obj = zend_object_store_get_object(path_obj->device_context TSRMLS_CC); RETURN_BOOL(PolyPolygon(dc_obj->hdc, points, point_counts, ints_in_count)); CLEANUP: efree(parameters); efree(points); efree(point_counts); }