static void test_addpie(void) { GpStatus status; GpPath *path; GdipCreatePath(FillModeAlternate, &path); /* NULL argument */ status = GdipAddPathPie(NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); expect(InvalidParameter, status); status = GdipAddPathPie(path, 0.0, 0.0, 100.0, 50.0, 10.0, 50.0); expect(Ok, status); ok_path(path, addpie_path, sizeof(addpie_path)/sizeof(path_test_t), FALSE); status = GdipResetPath(path); expect(Ok, status); /* zero width base ellipse */ status = GdipAddPathPie(path, 0.0, 0.0, 0.0, 60.0, -90.0, 24.0); expect(InvalidParameter, status); ok_path(path, addpie_path2, sizeof(addpie_path2)/sizeof(path_test_t), FALSE); status = GdipResetPath(path); expect(Ok, status); /* zero height base ellipse */ status = GdipAddPathPie(path, 0.0, 0.0, 60.0, 0.0 , -90.0, 24.0); expect(InvalidParameter, status); ok_path(path, addpie_path3, sizeof(addpie_path3)/sizeof(path_test_t), FALSE); GdipDeletePath(path); }
static void test_flatten(void) { GpStatus status; GpPath *path; GpMatrix *m; status = GdipCreatePath(FillModeAlternate, &path); expect(Ok, status); status = GdipCreateMatrix(&m); expect(Ok, status); /* NULL arguments */ status = GdipFlattenPath(NULL, NULL, 0.0); expect(InvalidParameter, status); status = GdipFlattenPath(NULL, m, 0.0); expect(InvalidParameter, status); /* flatten empty path */ status = GdipFlattenPath(path, NULL, 1.0); expect(Ok, status); status = GdipTransformPath(path, 0); expect(Ok, status); status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 50.0); expect(Ok, status); status = GdipFlattenPath(path, NULL, 1.0); expect(Ok, status); ok_path(path, flattenellipse_path, sizeof(flattenellipse_path)/sizeof(path_test_t), TRUE); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 100.0); expect(Ok, status); status = GdipFlattenPath(path, NULL, 1.0); expect(Ok, status); ok_path(path, flattenline_path, sizeof(flattenline_path)/sizeof(path_test_t), FALSE); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 50.0, 0.0, 90.0); expect(Ok, status); status = GdipFlattenPath(path, NULL, 1.0); expect(Ok, status); ok_path(path, flattenarc_path, sizeof(flattenarc_path)/sizeof(path_test_t), TRUE); /* easy case - quater of a full circle */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 100.0, 0.0, 90.0); expect(Ok, status); status = GdipFlattenPath(path, NULL, 1.0); expect(Ok, status); ok_path(path, flattenquater_path, sizeof(flattenquater_path)/sizeof(path_test_t), FALSE); GdipDeleteMatrix(m); GdipDeletePath(path); }
GpStatus WINGDIPAPI GdipPathIterNextSubpathPath(GpPathIterator* iter, INT* result, GpPath* path, BOOL* closed) { INT start, end; TRACE("(%p, %p, %p, %p)\n", iter, result, path, closed); if(!iter || !result || !closed) return InvalidParameter; GdipPathIterNextSubpath(iter, result, &start, &end, closed); /* return path */ if(((*result) > 0) && path){ GdipResetPath(path); if(!lengthen_path(path, *result)) return OutOfMemory; memcpy(path->pathdata.Points, &(iter->pathdata.Points[start]), sizeof(GpPointF)*(*result)); memcpy(path->pathdata.Types, &(iter->pathdata.Types[start]), sizeof(BYTE)*(*result)); path->pathdata.Count = *result; } return Ok; }
/*GDIplus is completely bugged here, we MUST build the gradient in local coord system and apply translation after, otherwise performances are just horrible*/ void gdip_recompute_radial_gradient(GF_STENCIL _this) { s32 repeat, k; u32 i; GpPointF pt; GpMatrix *mat; GPSTEN(); if (!_sten->needs_rebuild) return; _sten->needs_rebuild = GF_FALSE; if (_sten->pRadial) { GdipDeleteBrush(_sten->pRadial); _sten->pRadial = NULL; } if (_sten->pSolid) { GdipDeleteBrush(_sten->pSolid); _sten->pSolid = NULL; } if (_sten->circle) { GdipDeletePath(_sten->circle); _sten->circle = NULL; } GdipCreatePath(FillModeAlternate, &_sten->circle); /*get number of repeats*/ if (_sten->spread == GF_GRADIENT_MODE_PAD) { GdipAddPathEllipse(_sten->circle, - _sten->radius.X, -_sten->radius.Y, 2*_sten->radius.X, 2*_sten->radius.Y); GdipCreatePathGradientFromPath(_sten->circle, &_sten->pRadial); ARGB *blends = new ARGB[_sten->num_pos + 1]; /*radial blend pos are from bounds to center in gdiplus*/ blends[0] = _sten->cols[_sten->num_pos - 1]; for (i=0; i<_sten->num_pos;i++) { blends[i+1] = _sten->cols[_sten->num_pos - i - 1]; } REAL *pos = new REAL[_sten->num_pos + 1]; pos[0] = 0; for (i=0; i<_sten->num_pos;i++) { pos[i+1] = _sten->pos[i]; } GdipSetPathGradientPresetBlend(_sten->pRadial, blends, pos, _sten->num_pos + 1); delete [] blends; delete [] pos; /*set focal*/ pt = _sten->focal; pt.X -= _sten->center.X; pt.Y -= _sten->center.Y; GdipSetPathGradientCenterPoint(_sten->pRadial, &pt); /*set transform*/ GdipCreateMatrix(&mat); GdipTranslateMatrix(mat, _sten->center.X, _sten->center.Y, MatrixOrderAppend); if (_sten->pMat) GdipMultiplyMatrix(mat, _sten->pMat, MatrixOrderAppend); GdipSetTextureTransform((GpTexture*)_sten->pRadial, mat); GdipDeleteMatrix(mat); /*create back brush*/ GdipCreateSolidFill(_sten->cols[_sten->num_pos - 1], &_sten->pSolid); GdipResetPath(_sten->circle); GdipAddPathEllipse(_sten->circle, - _sten->radius.X + _sten->center.X, -_sten->radius.Y + _sten->center.Y, 2*_sten->radius.X, 2*_sten->radius.Y); } else { repeat = 10; GdipAddPathEllipse(_sten->circle, - repeat * _sten->radius.X, - repeat*_sten->radius.Y, 2*repeat*_sten->radius.X, 2*repeat*_sten->radius.Y); GdipCreatePathGradientFromPath(_sten->circle, &_sten->pRadial); GdipDeletePath(_sten->circle); _sten->circle = NULL; ARGB *blends = new ARGB[_sten->num_pos*repeat]; REAL *pos = new REAL[_sten->num_pos*repeat]; if (_sten->spread == GF_GRADIENT_MODE_REPEAT) { for (k=0; k<repeat; k++) { for (i=0; i<_sten->num_pos; i++) { blends[k*_sten->num_pos + i] = _sten->cols[_sten->num_pos - i - 1]; pos[k*_sten->num_pos + i] = (k + _sten->pos[i]) / repeat; } } } else { for (k=0; k<repeat; k++) { for (i=0; i<_sten->num_pos; i++) { u32 index = (k%2) ? (_sten->num_pos-i-1) : i; blends[k*_sten->num_pos + i] = _sten->cols[index]; if (k%2) { pos[k*_sten->num_pos + i] = (k + (1 - _sten->pos[index]) ) / repeat; } else { pos[k*_sten->num_pos + i] = ( k + _sten->pos[i] ) / repeat; } } } } GdipSetPathGradientPresetBlend(_sten->pRadial, blends, pos, _sten->num_pos*repeat); delete [] pos; delete [] blends; /*set focal*/ pt = _sten->focal; pt.X -= (1 - repeat) * (_sten->focal.X - _sten->center.X) + _sten->center.X; pt.Y -= (1 - repeat) * (_sten->focal.Y - _sten->center.Y) + _sten->center.Y; GdipSetPathGradientCenterPoint(_sten->pRadial, &pt); /*set transform*/ GdipCreateMatrix(&mat); GdipTranslateMatrix(mat, (1 - repeat) * (_sten->focal.X - _sten->center.X) + _sten->center.X, (1 - repeat) * (_sten->focal.Y - _sten->center.Y) + _sten->center.Y, MatrixOrderAppend); if (_sten->pMat) GdipMultiplyMatrix(mat, _sten->pMat, MatrixOrderAppend); GdipSetTextureTransform((GpTexture*)_sten->pRadial, mat); GdipDeleteMatrix(mat); GdipSetPathGradientWrapMode(_sten->pRadial, WrapModeTileFlipXY); } }
static void test_addcurve(void) { GpStatus status; GpPath *path; GpPointF points[4]; points[0].X = 0.0; points[0].Y = 0.0; points[1].X = 10.0; points[1].Y = 10.0; points[2].X = 10.0; points[2].Y = 20.0; points[3].X = 30.0; points[3].Y = 10.0; GdipCreatePath(FillModeAlternate, &path); /* NULL args */ status = GdipAddPathCurve2(NULL, NULL, 0, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve2(path, NULL, 0, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve2(path, points, -1, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve2(path, points, 1, 1.0); expect(InvalidParameter, status); /* add to empty path */ status = GdipAddPathCurve2(path, points, 4, 1.0); expect(Ok, status); ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE); GdipDeletePath(path); /* add to notempty path and opened figure */ GdipCreatePath(FillModeAlternate, &path); GdipAddPathLine(path, 100.0, 120.0, 123.0, 10.0); status = GdipAddPathCurve2(path, points, 4, 1.0); expect(Ok, status); ok_path(path, addcurve_path2, sizeof(addcurve_path2)/sizeof(path_test_t), FALSE); /* NULL args */ GdipResetPath(path); status = GdipAddPathCurve3(NULL, NULL, 0, 0, 0, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve3(path, NULL, 0, 0, 0, 0.0); expect(InvalidParameter, status); /* wrong count, offset.. */ status = GdipAddPathCurve3(path, points, 0, 0, 0, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve3(path, points, 4, 0, 0, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve3(path, points, 4, 0, 4, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve3(path, points, 4, 1, 3, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve3(path, points, 4, 1, 0, 0.0); expect(InvalidParameter, status); status = GdipAddPathCurve3(path, points, 4, 3, 1, 0.0); expect(InvalidParameter, status); /* use all points */ status = GdipAddPathCurve3(path, points, 4, 0, 3, 1.0); expect(Ok, status); ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE); GdipResetPath(path); status = GdipAddPathCurve3(path, points, 4, 1, 2, 1.0); expect(Ok, status); ok_path(path, addcurve_path3, sizeof(addcurve_path3)/sizeof(path_test_t), FALSE); GdipDeletePath(path); }
static void test_widen(void) { GpStatus status; GpPath *path; GpPen *pen; GpMatrix *m; INT count=-1; status = GdipCreatePath(FillModeAlternate, &path); expect(Ok, status); status = GdipCreatePen1(0xffffffff, 10.0, UnitPixel, &pen); expect(Ok, status); status = GdipCreateMatrix(&m); expect(Ok, status); /* NULL arguments */ status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(NULL, NULL, NULL, 0.0); expect(InvalidParameter, status); status = GdipWidenPath(path, pen, m, 0.0); expect(Ok, status); status = GdipWidenPath(path, pen, NULL, 1.0); expect(Ok, status); status = GdipWidenPath(path, NULL, m, 1.0); expect(InvalidParameter, status); status = GdipWidenPath(NULL, pen, m, 1.0); expect(InvalidParameter, status); /* widen empty path */ status = GdipResetPath(path); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(OutOfMemory, status); /* horizontal line */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* horizontal 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 2.5, 10.0, 25.0, 10.0); expect(Ok, status); status = GdipScaleMatrix(m, 2.0, 1.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* vertical 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 5.0, 50.0, 5.0); expect(Ok, status); status = GdipScaleMatrix(m, 0.5, 2.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); status = GdipScaleMatrix(m, 1.0, 0.5, MatrixOrderAppend); expect(Ok, status); /* dashed line */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 5.0, 50.0, 5.0); expect(Ok, status); status = GdipSetPenDashStyle(pen, DashStyleDash); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_dash_path, sizeof(widenline_dash_path)/sizeof(path_test_t), FALSE); status = GdipSetPenDashStyle(pen, DashStyleSolid); expect(Ok, status); /* pen width in UnitWorld */ GdipDeletePen(pen); status = GdipCreatePen1(0xffffffff, 10.0, UnitWorld, &pen); expect(Ok, status); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* horizontal 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 2.5, 10.0, 25.0, 10.0); expect(Ok, status); status = GdipScaleMatrix(m, 2.0, 1.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* vertical 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 5.0, 50.0, 5.0); expect(Ok, status); status = GdipScaleMatrix(m, 0.5, 2.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_wide_path, sizeof(widenline_wide_path)/sizeof(path_test_t), FALSE); status = GdipScaleMatrix(m, 1.0, 0.5, MatrixOrderAppend); expect(Ok, status); /* pen width in UnitInch */ GdipDeletePen(pen); status = GdipCreatePen1(0xffffffff, 10.0, UnitWorld, &pen); expect(Ok, status); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* pen width = 0 pixels - native fails to widen but can draw with this pen */ GdipDeletePen(pen); status = GdipCreatePen1(0xffffffff, 0.0, UnitPixel, &pen); expect(Ok, status); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); status = GdipGetPointCount(path, &count); expect(Ok, status); todo_wine expect(0, count); GdipDeleteMatrix(m); GdipDeletePen(pen); GdipDeletePath(path); }
static void test_widen(void) { GpStatus status; GpPath *path; GpPen *pen; GpMatrix *m; status = GdipCreatePath(FillModeAlternate, &path); expect(Ok, status); status = GdipCreatePen1(0xffffffff, 10.0, UnitPixel, &pen); expect(Ok, status); status = GdipCreateMatrix(&m); expect(Ok, status); /* NULL arguments */ status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(NULL, NULL, NULL, 0.0); expect(InvalidParameter, status); status = GdipWidenPath(path, pen, m, 0.0); expect(Ok, status); status = GdipWidenPath(path, pen, NULL, 1.0); expect(Ok, status); status = GdipWidenPath(path, NULL, m, 1.0); expect(InvalidParameter, status); status = GdipWidenPath(NULL, pen, m, 1.0); expect(InvalidParameter, status); /* widen empty path */ status = GdipResetPath(path); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(OutOfMemory, status); /* horizontal line */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* horizontal 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 2.5, 10.0, 25.0, 10.0); expect(Ok, status); status = GdipScaleMatrix(m, 2.0, 1.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* vertical 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 5.0, 50.0, 5.0); expect(Ok, status); status = GdipScaleMatrix(m, 0.5, 2.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); status = GdipScaleMatrix(m, 1.0, 0.5, MatrixOrderAppend); expect(Ok, status); /* pen width in UnitWorld */ GdipDeletePen(pen); status = GdipCreatePen1(0xffffffff, 10.0, UnitWorld, &pen); expect(Ok, status); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* horizontal 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 2.5, 10.0, 25.0, 10.0); expect(Ok, status); status = GdipScaleMatrix(m, 2.0, 1.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); /* vertical 2x stretch */ status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 5.0, 50.0, 5.0); expect(Ok, status); status = GdipScaleMatrix(m, 0.5, 2.0, MatrixOrderAppend); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_wide_path, sizeof(widenline_wide_path)/sizeof(path_test_t), FALSE); status = GdipScaleMatrix(m, 1.0, 0.5, MatrixOrderAppend); expect(Ok, status); /* pen width in UnitInch */ GdipDeletePen(pen); status = GdipCreatePen1(0xffffffff, 10.0, UnitWorld, &pen); expect(Ok, status); status = GdipResetPath(path); expect(Ok, status); status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); expect(Ok, status); status = GdipWidenPath(path, pen, m, 1.0); expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); GdipDeleteMatrix(m); GdipDeletePen(pen); GdipDeletePath(path); }
static GF_Glyph *gdip_load_glyph(GF_FontReader *dr, u32 glyph_name) { GF_Rect bounds; GF_Glyph *glyph; GpPath *path_tmp; GpStringFormat *fmt; GpMatrix *mat; Float est_advance_h; unsigned short str[4]; int i; FontPriv *ctx = (FontPriv *)dr->udta; if (!ctx->font) return NULL; RectF rc; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipCreateStringFormat(StringFormatFlagsNoWrap | StringFormatFlagsNoFitBlackBox | StringFormatFlagsMeasureTrailingSpaces, LANG_NEUTRAL, &fmt); GdipSetStringFormatAlign(fmt, StringAlignmentNear); GdipCreatePath(FillModeAlternate, &path_tmp); if (glyph_name==0x20) { est_advance_h = ctx->whitespace_width; } else { /*to compute first glyph alignment (say 'x', we figure out its bounding full box by using the '_' char as wrapper (eg, "_x_") then the bounding box starting from xMin of the glyph ('x_'). The difference between both will give us a good approx of the glyph alignment*/ str[0] = glyph_name; str[1] = (unsigned short) '_'; str[2] = (unsigned short) 0; GdipAddPathString(path_tmp, (const WCHAR *)str, -1, ctx->font, ctx->font_style, ctx->em_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); est_advance_h = rc.Width - ctx->underscore_width; } GdipResetPath(path_tmp); str[0] = glyph_name; str[1] = (unsigned short) 0; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipAddPathString(path_tmp, (const WCHAR *)str, -1, ctx->font, ctx->font_style, ctx->em_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); /*flip so that we are in a font coordinate system - also move back the glyph to x=0 and y=baseline, GdiPlus doesn't do so*/ GdipCreateMatrix(&mat); GdipTranslateMatrix(mat, - rc.X, -ctx->ascent, MatrixOrderAppend); GdipScaleMatrix(mat, 1, -1, MatrixOrderAppend); GdipTransformPath(path_tmp, mat); GdipDeleteMatrix(mat); /*start enum*/ s32 count; GdipGetPointCount(path_tmp, &count); GpPointF *pts = new GpPointF[count]; BYTE *types = new BYTE[count]; GdipGetPathTypes(path_tmp, types, count); GdipGetPathPoints(path_tmp, pts, count); GF_SAFEALLOC(glyph, GF_Glyph); GF_SAFEALLOC(glyph->path, GF_Path); for (i=0; i<count; ) { BOOL closed = 0; s32 sub_type; sub_type = types[i] & PathPointTypePathTypeMask; if (sub_type == PathPointTypeStart) { gf_path_add_move_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y)); i++; } else if (sub_type == PathPointTypeLine) { gf_path_add_line_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y)); if (types[i] & PathPointTypeCloseSubpath) gf_path_close(glyph->path); i++; } else if (sub_type == PathPointTypeBezier) { assert(i+2<=count); gf_path_add_cubic_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y), FLT2FIX(pts[i+1].X), FLT2FIX(pts[i+1].Y), FLT2FIX(pts[i+2].X), FLT2FIX(pts[i+2].Y)); if (types[i+2] & PathPointTypeCloseSubpath) gf_path_close(glyph->path); i += 3; } else { assert(0); break; } } delete [] pts; delete [] types; GdipDeleteStringFormat(fmt); GdipDeletePath(path_tmp); glyph->ID = glyph_name; glyph->utf_name = glyph_name; glyph->vert_advance = (s32) (ctx->ascent-ctx->descent); glyph->horiz_advance = (s32) est_advance_h; gf_path_get_bounds(glyph->path, &bounds); glyph->width = FIX2INT(bounds.width); glyph->height = FIX2INT(bounds.height); return glyph; }
static M4Err gdip_add_text_to_path(FontRaster *dr, LPM4PATH path, Bool flipText, const unsigned short* string, Float left, Float top, Float x_scaling, Float y_scaling, Float ascent, M4Rect *bounds) { GpPath *path_tmp; GpMatrix *mat; GpStringFormat *fmt; Float real_start; unsigned short str[4]; FontPriv *ctx = (FontPriv *)dr->priv; if (!ctx->font) return M4BadParam; RectF rc; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; /*find first non-space char and estimate its glyph pos since GDIplus doesn't give this info*/ s32 len = utf8_wcslen(string); s32 i=0; for (; i<len; i++) { if (string[i] != (unsigned short) ' ') break; } if (i>=len) return M4OK; GdipCreateStringFormat(StringFormatFlagsNoWrap | StringFormatFlagsNoFitBlackBox | StringFormatFlagsMeasureTrailingSpaces, LANG_NEUTRAL, &fmt); GdipSetStringFormatAlign(fmt, StringAlignmentNear); GdipCreatePath(FillModeAlternate, &path_tmp); /*to compute first glyph alignment (say 'x', we figure out its bounding full box by using the '_' char as wrapper (eg, "_x_") then the bounding box starting from xMin of the glyph ('x_'). The difference between both will give us a good approx of the glyph alignment*/ str[0] = (unsigned short) '_'; str[1] = string[i]; str[2] = (unsigned short) '_'; str[3] = (unsigned short) 0; GdipAddPathString(path_tmp, str, -1, ctx->font, ctx->font_style, ctx->font_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); Float w1 = rc.Width - 2 * ctx->underscore_width; GdipResetPath(path_tmp); str[0] = string[i]; str[1] = (unsigned short) '_'; str[2] = (unsigned short) 0; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipAddPathString(path_tmp, str, -1, ctx->font, ctx->font_style, ctx->font_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); real_start = w1 - (rc.Width - ctx->underscore_width); GdipResetPath(path_tmp); rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipAddPathString(path_tmp, string, -1, ctx->font, ctx->font_style, ctx->font_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); GdipCreateMatrix(&mat); Float off_left = rc.X; Float off_left_real = rc.X; /*adjust all white space at begin*/ adjust_white_space(string, &off_left, -1*ctx->whitespace_width); if (flipText) { /*first translate in local system*/ GdipTranslateMatrix(mat, left - off_left + real_start, -top, MatrixOrderAppend); /*then scale as specified*/ GdipScaleMatrix(mat, x_scaling, -y_scaling, MatrixOrderAppend); } else { /*first translate in local system*/ GdipTranslateMatrix(mat, left - off_left + real_start, top-ascent, MatrixOrderAppend); /*then scale as specified*/ GdipScaleMatrix(mat, x_scaling, y_scaling, MatrixOrderAppend); } GdipTransformPath(path_tmp, mat); /*start enum*/ s32 count; GdipGetPointCount(path_tmp, &count); GpPointF *pts = new GpPointF[count]; BYTE *types = new BYTE[count]; GdipGetPathTypes(path_tmp, types, count); GdipGetPathPoints(path_tmp, pts, count); for (i=0; i<count; ) { BOOL closed = 0; s32 sub_type; sub_type = types[i] & PathPointTypePathTypeMask; if (sub_type == PathPointTypeStart) { m4_path_add_move_to(path, pts[i].X, pts[i].Y); i++; } else if (sub_type == PathPointTypeLine) { m4_path_add_line_to(path, pts[i].X, pts[i].Y); if (types[i] & PathPointTypeCloseSubpath) m4_path_close(path); i++; } else if (sub_type == PathPointTypeBezier) { assert(i+2<=count); m4_path_add_cubic_to(path, pts[i].X, pts[i].Y, pts[i+1].X, pts[i+1].Y, pts[i+2].X, pts[i+2].Y); if (types[i+2] & PathPointTypeCloseSubpath) m4_path_close(path); i += 3; } else { assert(0); break; } } delete [] pts; delete [] types; GdipResetPath(path_tmp); adjust_white_space(string, &rc.Width, ctx->whitespace_width); rc.X = off_left_real; rc.X = off_left; /*special case where string is just space*/ if (!rc.Height) rc.Height = 1; GdipAddPathRectangles(path_tmp, &rc, 1); GdipGetPathWorldBounds(path_tmp, &rc, mat, NULL); bounds->x = rc.X; bounds->y = rc.Y; bounds->width = rc.Width; bounds->height = rc.Height; GdipDeleteStringFormat(fmt); GdipDeletePath(path_tmp); GdipDeleteMatrix(mat); return M4OK; }