// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Quadratics allowQuadratics, ReduceOrder_Styles reduceStyle) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].x > cubic[index].x) { minX = index; } if (cubic[minY].y > cubic[index].y) { minY = index; } if (cubic[maxX].x < cubic[index].x) { maxX = index; } if (cubic[maxY].y < cubic[index].y) { maxY = index; } } for (index = 0; index < 4; ++index) { double cx = cubic[index].x; double cy = cubic[index].y; double denom = SkTMax(fabs(cx), SkTMax(fabs(cy), SkTMax(fabs(cubic[minX].x), fabs(cubic[minY].y)))); if (denom == 0) { minXSet |= 1 << index; minYSet |= 1 << index; continue; } double inv = 1 / denom; if (approximately_equal_half(cx * inv, cubic[minX].x * inv)) { minXSet |= 1 << index; } if (approximately_equal_half(cy * inv, cubic[minY].y * inv)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, reduction); } return vertical_line(cubic, reduceStyle, reduction); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, reduceStyle, reduction); } int result = check_linear(cubic, reduceStyle, minX, maxX, minY, maxY, reduction); if (result) { return result; } if (allowQuadratics == kReduceOrder_QuadraticsAllowed && (result = check_quadratic(cubic, reduction))) { return result; } memcpy(reduction, cubic, sizeof(Cubic)); return 4; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int SkReduceOrder::reduce(const SkDCubic& cubic, Quadratics allowQuadratics) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].fX > cubic[index].fX) { minX = index; } if (cubic[minY].fY > cubic[index].fY) { minY = index; } if (cubic[maxX].fX < cubic[index].fX) { maxX = index; } if (cubic[maxY].fY < cubic[index].fY) { maxY = index; } } for (index = 0; index < 4; ++index) { double cx = cubic[index].fX; double cy = cubic[index].fY; double denom = SkTMax(fabs(cx), SkTMax(fabs(cy), SkTMax(fabs(cubic[minX].fX), fabs(cubic[minY].fY)))); if (denom == 0) { minXSet |= 1 << index; minYSet |= 1 << index; continue; } double inv = 1 / denom; if (approximately_equal_half(cx * inv, cubic[minX].fX * inv)) { minXSet |= 1 << index; } if (approximately_equal_half(cy * inv, cubic[minY].fY * inv)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, fCubic); } return vertical_line(cubic, fCubic); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, fCubic); } int result = check_linear(cubic, minX, maxX, minY, maxY, fCubic); if (result) { return result; } if (allowQuadratics == SkReduceOrder::kAllow_Quadratics && (result = check_quadratic(cubic, fCubic))) { return result; } fCubic = cubic; return 4; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Flags allowQuadratics) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].x > cubic[index].x) { minX = index; } if (cubic[minY].y > cubic[index].y) { minY = index; } if (cubic[maxX].x < cubic[index].x) { maxX = index; } if (cubic[maxY].y < cubic[index].y) { maxY = index; } } for (index = 0; index < 4; ++index) { if (approximately_equal(cubic[index].x, cubic[minX].x)) { minXSet |= 1 << index; } if (approximately_equal(cubic[index].y, cubic[minY].y)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, reduction); } return vertical_line(cubic, reduction); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, reduction); } int result = check_linear(cubic, reduction, minX, maxX, minY, maxY); if (result) { return result; } if (allowQuadratics && (result = check_quadratic(cubic, reduction))) { return result; } memcpy(reduction, cubic, sizeof(Cubic)); return 4; }
void STDMETHODCALLTYPE SkDWriteGeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) { SkPoint lastPt; fPath->getLastPt(&lastPt); D2D1_POINT_2F prevPt = { SkScalarToFloat(lastPt.fX), SkScalarToFloat(lastPt.fY) }; for (const D2D1_BEZIER_SEGMENT *end = &beziers[beziersCount]; beziers < end; ++beziers) { Cubic cubic = { { prevPt.x, prevPt.y }, { beziers->point1.x, beziers->point1.y }, { beziers->point2.x, beziers->point2.y }, { beziers->point3.x, beziers->point3.y }, }; Quadratic quadratic; if (check_quadratic(cubic, quadratic)) { fPath->quadTo(quadratic[1].x, quadratic[1].y, quadratic[2].x, quadratic[2].y); } else { fPath->cubicTo(beziers->point1.x, beziers->point1.y, beziers->point2.x, beziers->point2.y, beziers->point3.x, beziers->point3.y); } prevPt = beziers->point3; } }