本文整理汇总了C++中SkPath类的典型用法代码示例。如果您正苦于以下问题:C++ SkPath类的具体用法?C++ SkPath怎么用?C++ SkPath使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了SkPath类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: line_to
void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY);
fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY);
}
示例2: SkChopCubicAtMaxCurvature
void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2,
const SkPoint& pt3) {
bool degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
bool degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
bool degenerateCD = SkPath::IsLineDegenerate(pt2, pt3);
if (degenerateAB + degenerateBC + degenerateCD >= 2) {
this->lineTo(pt3);
return;
}
SkVector normalAB, unitAB, normalCD, unitCD;
// find the first tangent (which might be pt1 or pt2
{
const SkPoint* nextPt = &pt1;
if (degenerateAB)
nextPt = &pt2;
this->preJoinTo(*nextPt, &normalAB, &unitAB, false);
}
{
SkPoint pts[4], tmp[13];
int i, count;
SkVector n, u;
SkScalar tValues[3];
pts[0] = fPrevPt;
pts[1] = pt1;
pts[2] = pt2;
pts[3] = pt3;
#if 1
count = SkChopCubicAtMaxCurvature(pts, tmp, tValues);
#else
count = 1;
memcpy(tmp, pts, 4 * sizeof(SkPoint));
#endif
n = normalAB;
u = unitAB;
for (i = 0; i < count; i++) {
this->cubic_to(&tmp[i * 3], n, u, &normalCD, &unitCD,
kMaxCubicSubdivide);
if (i == count - 1) {
break;
}
n = normalCD;
u = unitCD;
}
// check for too pinchy
for (i = 1; i < count; i++) {
SkPoint p;
SkVector v, c;
SkEvalCubicAt(pts, tValues[i - 1], &p, &v, &c);
SkScalar dot = SkPoint::DotProduct(c, c);
v.scale(SkScalarInvert(dot));
if (SkScalarNearlyZero(v.fX) && SkScalarNearlyZero(v.fY)) {
fExtra.addCircle(p.fX, p.fY, fRadius, SkPath::kCW_Direction);
}
}
}
this->postJoinTo(pt3, normalCD, unitCD);
}
示例3: testPath
static SkPath testPath() {
SkPath path;
path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
SkIntToScalar(2), SkIntToScalar(1)));
return path;
}
示例4: generatePath
void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
SkPath* devPath, SkMatrix* fillToDevMatrix) {
SkPath path;
generatePath(glyph, &path);
if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
SkFixed dx = glyph.getSubXFixed();
SkFixed dy = glyph.getSubYFixed();
if (dx | dy) {
path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
}
}
if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
// need the path in user-space, with only the point-size applied
// so that our stroking and effects will operate the same way they
// would if the user had extracted the path themself, and then
// called drawPath
SkPath localPath;
SkMatrix matrix, inverse;
fRec.getMatrixFrom2x2(&matrix);
if (!matrix.invert(&inverse)) {
// assume fillPath and devPath are already empty.
return;
}
path.transform(inverse, &localPath);
// now localPath is only affected by the paint settings, and not the canvas matrix
SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
if (fRec.fFrameWidth > 0) {
rec.setStrokeStyle(fRec.fFrameWidth,
SkToBool(fRec.fFlags & kFrameAndFill_Flag));
// glyphs are always closed contours, so cap type is ignored,
// so we just pass something.
rec.setStrokeParams(SkPaint::kButt_Cap,
(SkPaint::Join)fRec.fStrokeJoin,
fRec.fMiterLimit);
}
if (fPathEffect) {
SkPath effectPath;
if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
localPath.swap(effectPath);
}
}
if (rec.needToApply()) {
SkPath strokePath;
if (rec.applyToPath(&strokePath, localPath)) {
localPath.swap(strokePath);
}
}
// now return stuff to the caller
if (fillToDevMatrix) {
*fillToDevMatrix = matrix;
}
if (devPath) {
localPath.transform(matrix, devPath);
}
if (fillPath) {
fillPath->swap(localPath);
}
} else { // nothing tricky to do
if (fillToDevMatrix) {
fillToDevMatrix->reset();
}
if (devPath) {
if (fillPath == NULL) {
devPath->swap(path);
} else {
*devPath = path;
}
}
if (fillPath) {
fillPath->swap(path);
}
}
if (devPath) {
devPath->updateBoundsCache();
}
if (fillPath) {
fillPath->updateBoundsCache();
}
}
示例5: SkASSERT
void GrGLPath::InitPathObject(GrGLGpu* gpu,
GrGLuint pathID,
const SkPath& skPath,
const GrStrokeInfo& stroke) {
SkASSERT(!stroke.isDashed());
if (!skPath.isEmpty()) {
int verbCnt = skPath.countVerbs();
int pointCnt = skPath.countPoints();
int minCoordCnt = pointCnt * 2;
SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
SkDEBUGCODE(int numCoords = 0);
if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
// This branch does type punning, converting SkPoint* to GrGLfloat*.
SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, sk_point_not_two_floats);
// This branch does not convert with SkScalarToFloat.
#ifndef SK_SCALAR_IS_FLOAT
#error Need SK_SCALAR_IS_FLOAT.
#endif
pathCommands.resize_back(verbCnt);
pathCoords.resize_back(minCoordCnt);
skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
skPath.getVerbs(&pathCommands[0], verbCnt);
for (int i = 0; i < verbCnt; ++i) {
SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
pathCommands[i] = verb_to_gl_path_cmd(v);
SkDEBUGCODE(numCoords += num_coords(v));
}
} else {
SkPoint points[4];
SkPath::RawIter iter(skPath);
SkPath::Verb verb;
while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
pathCommands.push_back(verb_to_gl_path_cmd(verb));
GrGLfloat coords[6];
int coordsForVerb;
switch (verb) {
case SkPath::kMove_Verb:
points_to_coords(points, 0, 1, coords);
coordsForVerb = 2;
break;
case SkPath::kLine_Verb:
points_to_coords(points, 1, 1, coords);
coordsForVerb = 2;
break;
case SkPath::kConic_Verb:
points_to_coords(points, 1, 2, coords);
coords[4] = SkScalarToFloat(iter.conicWeight());
coordsForVerb = 5;
break;
case SkPath::kQuad_Verb:
points_to_coords(points, 1, 2, coords);
coordsForVerb = 4;
break;
case SkPath::kCubic_Verb:
points_to_coords(points, 1, 3, coords);
coordsForVerb = 6;
break;
case SkPath::kClose_Verb:
continue;
default:
SkASSERT(false); // Not reached.
continue;
}
SkDEBUGCODE(numCoords += num_coords(verb));
pathCoords.push_back_n(coordsForVerb, coords);
}
}
SkASSERT(verbCnt == pathCommands.count());
SkASSERT(numCoords == pathCoords.count());
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
pathCoords.count(), GR_GL_FLOAT, &pathCoords[0]));
} else {
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, NULL, 0, GR_GL_FLOAT, NULL));
}
if (stroke.needToApply()) {
SkASSERT(!stroke.isHairlineStyle());
GR_GL_CALL(gpu->glInterface(),
PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
GR_GL_CALL(gpu->glInterface(),
PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
GrGLenum join = join_to_gl_join(stroke.getJoin());
GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
GrGLenum cap = cap_to_gl_cap(stroke.getCap());
GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
}
}
示例6: get_geometry
static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices,
PLSVertices& quadVertices, GrResourceProvider* resourceProvider,
SkRect bounds) {
SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds);
int contourCnt;
int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol);
if (maxPts <= 0) {
return 0;
}
SkPath linesOnlyPath;
linesOnlyPath.setFillType(path.getFillType());
SkSTArray<15, SkPoint, true> quadPoints;
SkPath::Iter iter(path, true);
bool done = false;
while (!done) {
SkPoint pts[4];
SkPath::Verb verb = iter.next(pts);
switch (verb) {
case SkPath::kMove_Verb:
SkASSERT(quadPoints.count() % 3 == 0);
for (int i = 0; i < quadPoints.count(); i += 3) {
add_quad(&quadPoints[i], quadVertices);
}
quadPoints.reset();
m.mapPoints(&pts[0], 1);
linesOnlyPath.moveTo(pts[0]);
break;
case SkPath::kLine_Verb:
m.mapPoints(&pts[1], 1);
linesOnlyPath.lineTo(pts[1]);
break;
case SkPath::kQuad_Verb:
m.mapPoints(pts, 3);
linesOnlyPath.lineTo(pts[2]);
quadPoints.push_back(pts[0]);
quadPoints.push_back(pts[1]);
quadPoints.push_back(pts[2]);
break;
case SkPath::kCubic_Verb: {
m.mapPoints(pts, 4);
SkSTArray<15, SkPoint, true> quads;
GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, &quads);
int count = quads.count();
for (int q = 0; q < count; q += 3) {
linesOnlyPath.lineTo(quads[q + 2]);
quadPoints.push_back(quads[q]);
quadPoints.push_back(quads[q + 1]);
quadPoints.push_back(quads[q + 2]);
}
break;
}
case SkPath::kConic_Verb: {
m.mapPoints(pts, 3);
SkScalar weight = iter.conicWeight();
SkAutoConicToQuads converter;
const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance);
int count = converter.countQuads();
for (int i = 0; i < count; ++i) {
linesOnlyPath.lineTo(quads[2 * i + 2]);
quadPoints.push_back(quads[2 * i]);
quadPoints.push_back(quads[2 * i + 1]);
quadPoints.push_back(quads[2 * i + 2]);
}
break;
}
case SkPath::kClose_Verb:
linesOnlyPath.close();
break;
case SkPath::kDone_Verb:
done = true;
break;
default: SkASSERT(false);
}
}
SkASSERT(quadPoints.count() % 3 == 0);
for (int i = 0; i < quadPoints.count(); i += 3) {
add_quad(&quadPoints[i], quadVertices);
}
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey key;
GrUniqueKey::Builder builder(&key, kDomain, 2);
builder[0] = path.getGenerationID();
builder[1] = path.getFillType();
builder.finish();
GrTessellator::WindingVertex* windingVertices;
int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices);
if (triVertexCount > 0) {
for (int i = 0; i < triVertexCount; i += 3) {
SkPoint p1 = windingVertices[i].fPos;
SkPoint p2 = windingVertices[i + 1].fPos;
SkPoint p3 = windingVertices[i + 2].fPos;
int winding = windingVertices[i].fWinding;
SkASSERT(windingVertices[i + 1].fWinding == winding);
SkASSERT(windingVertices[i + 2].fWinding == winding);
SkScalar cross = (p2 - p1).cross(p3 - p1);
SkPoint bloated[3] = { p1, p2, p3 };
if (cross < 0.0f) {
SkTSwap(p1, p3);
//.........这里部分代码省略.........
示例7: internalGetPath
void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix)
{
SkPath path;
this->getGlyphContext(glyph)->generatePath(glyph, &path);
if (fRec.fFrameWidth > 0 || fPathEffect != NULL)
{
// need the path in user-space, with only the point-size applied
// so that our stroking and effects will operate the same way they
// would if the user had extracted the path themself, and then
// called drawPath
SkPath localPath;
SkMatrix matrix, inverse;
fRec.getMatrixFrom2x2(&matrix);
matrix.invert(&inverse);
path.transform(inverse, &localPath);
// now localPath is only affected by the paint settings, and not the canvas matrix
SkScalar width = fRec.fFrameWidth;
if (fPathEffect)
{
SkPath effectPath;
if (fPathEffect->filterPath(&effectPath, localPath, &width))
localPath.swap(effectPath);
}
if (width > 0)
{
SkStroke stroker;
SkPath outline;
stroker.setWidth(width);
stroker.setMiterLimit(fRec.fMiterLimit);
stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
stroker.strokePath(localPath, &outline);
localPath.swap(outline);
}
// now return stuff to the caller
if (fillToDevMatrix)
*fillToDevMatrix = matrix;
if (devPath)
localPath.transform(matrix, devPath);
if (fillPath)
fillPath->swap(localPath);
}
else // nothing tricky to do
{
if (fillToDevMatrix)
fillToDevMatrix->reset();
if (devPath)
{
if (fillPath == NULL)
devPath->swap(path);
else
*devPath = path;
}
if (fillPath)
fillPath->swap(path);
}
if (devPath)
devPath->updateBoundsCache();
if (fillPath)
fillPath->updateBoundsCache();
}
示例8: asPoints
// Currently asPoints is more restrictive then it needs to be. In the future
// we need to:
// allow kRound_Cap capping (could allow rotations in the matrix with this)
// allow paths to be returned
bool SkDashImpl::asPoints(PointData* results, const SkPath& src, const SkStrokeRec& rec,
const SkMatrix& matrix, const SkRect* cullRect) const {
// width < 0 -> fill && width == 0 -> hairline so requiring width > 0 rules both out
if (0 >= rec.getWidth()) {
return false;
}
// TODO: this next test could be eased up. We could allow any number of
// intervals as long as all the ons match and all the offs match.
// Additionally, they do not necessarily need to be integers.
// We cannot allow arbitrary intervals since we want the returned points
// to be uniformly sized.
if (fCount != 2 ||
!SkScalarNearlyEqual(fIntervals[0], fIntervals[1]) ||
!SkScalarIsInt(fIntervals[0]) ||
!SkScalarIsInt(fIntervals[1])) {
return false;
}
SkPoint pts[2];
if (!src.isLine(pts)) {
return false;
}
// TODO: this test could be eased up to allow circles
if (SkPaint::kButt_Cap != rec.getCap()) {
return false;
}
// TODO: this test could be eased up for circles. Rotations could be allowed.
if (!matrix.rectStaysRect()) {
return false;
}
// See if the line can be limited to something plausible.
if (!cull_line(pts, rec, matrix, cullRect, fIntervalLength)) {
return false;
}
SkScalar length = SkPoint::Distance(pts[1], pts[0]);
SkVector tangent = pts[1] - pts[0];
if (tangent.isZero()) {
return false;
}
tangent.scale(SkScalarInvert(length));
// TODO: make this test for horizontal & vertical lines more robust
bool isXAxis = true;
if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) ||
SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) {
results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth()));
} else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) ||
SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) {
results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0]));
isXAxis = false;
} else if (SkPaint::kRound_Cap != rec.getCap()) {
// Angled lines don't have axis-aligned boxes.
return false;
}
if (results) {
results->fFlags = 0;
SkScalar clampedInitialDashLength = SkMinScalar(length, fInitialDashLength);
if (SkPaint::kRound_Cap == rec.getCap()) {
results->fFlags |= PointData::kCircles_PointFlag;
}
results->fNumPoints = 0;
SkScalar len2 = length;
if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) {
SkASSERT(len2 >= clampedInitialDashLength);
if (0 == fInitialDashIndex) {
if (clampedInitialDashLength > 0) {
if (clampedInitialDashLength >= fIntervals[0]) {
++results->fNumPoints; // partial first dash
}
len2 -= clampedInitialDashLength;
}
len2 -= fIntervals[1]; // also skip first space
if (len2 < 0) {
len2 = 0;
}
} else {
len2 -= clampedInitialDashLength; // skip initial partial empty
}
}
// Too many midpoints can cause results->fNumPoints to overflow or
// otherwise cause the results->fPoints allocation below to OOM.
// Cap it to a sane value.
SkScalar numIntervals = len2 / fIntervalLength;
if (!SkScalarIsFinite(numIntervals) || numIntervals > SkDashPath::kMaxDashCount) {
return false;
//.........这里部分代码省略.........
示例9: SkASSERT
void GrCCFiller::PathInfo::tessellateFan(const GrCCFillGeometry& geometry, int verbsIdx,
int ptsIdx, const SkIRect& clippedDevIBounds,
PrimitiveTallies* newTriangleCounts) {
using Verb = GrCCFillGeometry::Verb;
SkASSERT(-1 == fFanTessellationCount);
SkASSERT(!fFanTessellation);
const SkTArray<Verb, true>& verbs = geometry.verbs();
const SkTArray<SkPoint, true>& pts = geometry.points();
newTriangleCounts->fTriangles =
newTriangleCounts->fWeightedTriangles = 0;
// Build an SkPath of the Redbook fan. We use "winding" fill type right now because we are
// producing a coverage count, and must fill in every region that has non-zero wind. The
// path processor will convert coverage count to the appropriate fill type later.
SkPath fan;
fan.setFillType(SkPath::kWinding_FillType);
SkASSERT(Verb::kBeginPath == verbs[verbsIdx]);
for (int i = verbsIdx + 1; i < verbs.count(); ++i) {
switch (verbs[i]) {
case Verb::kBeginPath:
SK_ABORT("Invalid GrCCFillGeometry");
continue;
case Verb::kBeginContour:
fan.moveTo(pts[ptsIdx++]);
continue;
case Verb::kLineTo:
fan.lineTo(pts[ptsIdx++]);
continue;
case Verb::kMonotonicQuadraticTo:
case Verb::kMonotonicConicTo:
fan.lineTo(pts[ptsIdx + 1]);
ptsIdx += 2;
continue;
case Verb::kMonotonicCubicTo:
fan.lineTo(pts[ptsIdx + 2]);
ptsIdx += 3;
continue;
case Verb::kEndClosedContour:
case Verb::kEndOpenContour:
fan.close();
continue;
}
}
GrTessellator::WindingVertex* vertices = nullptr;
fFanTessellationCount =
GrTessellator::PathToVertices(fan, std::numeric_limits<float>::infinity(),
SkRect::Make(clippedDevIBounds), &vertices);
if (fFanTessellationCount <= 0) {
SkASSERT(0 == fFanTessellationCount);
SkASSERT(nullptr == vertices);
return;
}
SkASSERT(0 == fFanTessellationCount % 3);
for (int i = 0; i < fFanTessellationCount; i += 3) {
int tessWinding = vertices[i].fWinding;
SkASSERT(tessWinding == vertices[i + 1].fWinding);
SkASSERT(tessWinding == vertices[i + 2].fWinding);
// Ensure this triangle's points actually wind in the same direction as tessWinding.
// CCPR shaders use the sign of wind to determine which direction to bloat, so even for
// "wound" triangles the winding sign and point ordering need to agree.
float ax = vertices[i].fPos.fX - vertices[i + 1].fPos.fX;
float ay = vertices[i].fPos.fY - vertices[i + 1].fPos.fY;
float bx = vertices[i].fPos.fX - vertices[i + 2].fPos.fX;
float by = vertices[i].fPos.fY - vertices[i + 2].fPos.fY;
float wind = ax*by - ay*bx;
if ((wind > 0) != (-tessWinding > 0)) { // Tessellator has opposite winding sense.
std::swap(vertices[i + 1].fPos, vertices[i + 2].fPos);
}
if (1 == abs(tessWinding)) {
++newTriangleCounts->fTriangles;
} else {
++newTriangleCounts->fWeightedTriangles;
}
}
fFanTessellation.reset(vertices);
}
示例10: create_concave_path
SkPath create_concave_path(const SkPoint& offset) {
SkPath concavePath;
concavePath.moveTo(kMin, kMin);
concavePath.lineTo(kMid, 105.0f);
concavePath.lineTo(kMax, kMin);
concavePath.lineTo(295.0f, kMid);
concavePath.lineTo(kMax, kMax);
concavePath.lineTo(kMid, 295.0f);
concavePath.lineTo(kMin, kMax);
concavePath.lineTo(105.0f, kMid);
concavePath.close();
concavePath.offset(offset.fX, offset.fY);
return concavePath;
}
示例11: create_path_22
// A quad which becomes NaN when interpolated.
static SkPath create_path_22() {
SkPath path;
path.moveTo(-5.71889e+13f, 1.36759e+09f);
path.quadTo(2.45472e+19f, -3.12406e+15f, -2.19589e+18f, 2.79462e+14f);
return path;
}
示例12: create_path_19
// Exercises the case where an edge becomes collinear with *two* of its
// adjacent neighbour edges after splitting.
// This is a reduction from
// http://mooooo.ooo/chebyshev-sine-approximation/horner_ulp.svg
static SkPath create_path_19() {
SkPath path;
path.moveTo( 351.99298095703125, 348.23046875);
path.lineTo( 351.91876220703125, 347.33984375);
path.lineTo( 351.91876220703125, 346.1953125);
path.lineTo( 351.90313720703125, 347.734375);
path.lineTo( 351.90313720703125, 346.1328125);
path.lineTo( 351.87579345703125, 347.93359375);
path.lineTo( 351.87579345703125, 345.484375);
path.lineTo( 351.86407470703125, 347.7890625);
path.lineTo( 351.86407470703125, 346.2109375);
path.lineTo( 351.84844970703125, 347.63763427734375);
path.lineTo( 351.84454345703125, 344.19232177734375);
path.lineTo( 351.78204345703125, 346.9483642578125);
path.lineTo( 351.758636474609375, 347.18310546875);
path.lineTo( 351.75469970703125, 346.75);
path.lineTo( 351.75469970703125, 345.46875);
path.lineTo( 352.5546875, 345.46875);
path.lineTo( 352.55078125, 347.01953125);
path.lineTo( 351.75079345703125, 347.02313232421875);
path.lineTo( 351.74688720703125, 346.15203857421875);
path.lineTo( 351.74688720703125, 347.646148681640625);
path.lineTo( 352.5390625, 346.94140625);
path.lineTo( 351.73907470703125, 346.94268798828125);
path.lineTo( 351.73516845703125, 344.48565673828125);
path.lineTo( 352.484375, 346.73828125);
path.lineTo( 351.68438720703125, 346.7401123046875);
path.lineTo( 352.4765625, 346.546875);
path.lineTo( 351.67657470703125, 346.54937744140625);
path.lineTo( 352.47265625, 346.75390625);
path.lineTo( 351.67266845703125, 346.756622314453125);
path.lineTo( 351.66876220703125, 345.612091064453125);
return path;
}
示例13: test_clip_bound_opt
static void test_clip_bound_opt(skiatest::Reporter* reporter) {
// Test for crbug.com/229011
SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
SkIntToScalar(2), SkIntToScalar(2));
SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
SkIntToScalar(1), SkIntToScalar(1));
SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
SkIntToScalar(1), SkIntToScalar(1));
SkPath invPath;
invPath.addOval(rect1);
invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
SkPath path;
path.addOval(rect2);
SkPath path2;
path2.addOval(rect3);
SkIRect clipBounds;
SkPictureRecorder recorder;
// Testing conservative-raster-clip that is enabled by PictureRecord
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
canvas->clipPath(invPath, SkRegion::kIntersect_Op);
bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
REPORTER_ASSERT(reporter, true == nonEmpty);
REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
}
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
canvas->clipPath(path, SkRegion::kIntersect_Op);
canvas->clipPath(invPath, SkRegion::kIntersect_Op);
bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
REPORTER_ASSERT(reporter, true == nonEmpty);
REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
}
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
canvas->clipPath(path, SkRegion::kIntersect_Op);
canvas->clipPath(invPath, SkRegion::kUnion_Op);
bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
REPORTER_ASSERT(reporter, true == nonEmpty);
REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
}
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
canvas->clipPath(path, SkRegion::kDifference_Op);
bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
REPORTER_ASSERT(reporter, true == nonEmpty);
REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
}
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
canvas->clipPath(path, SkRegion::kReverseDifference_Op);
bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
// True clip is actually empty in this case, but the best
// determination we can make using only bounds as input is that the
// clip is included in the bounds of 'path'.
REPORTER_ASSERT(reporter, true == nonEmpty);
REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
}
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
canvas->clipPath(path, SkRegion::kIntersect_Op);
canvas->clipPath(path2, SkRegion::kXOR_Op);
bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
REPORTER_ASSERT(reporter, true == nonEmpty);
REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
}
}
示例14: onDrawContent
virtual void onDrawContent(SkCanvas* canvas) {
SkPath path;
path.moveTo(SkIntToScalar(0), SkIntToScalar(50));
path.quadTo(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(50), SkIntToScalar(0));
path.lineTo(SkIntToScalar(175), SkIntToScalar(0));
path.quadTo(SkIntToScalar(200), SkIntToScalar(0), SkIntToScalar(200), SkIntToScalar(25));
path.lineTo(SkIntToScalar(200), SkIntToScalar(150));
path.quadTo(SkIntToScalar(200), SkIntToScalar(200), SkIntToScalar(150), SkIntToScalar(200));
path.lineTo(SkIntToScalar(0), SkIntToScalar(200));
path.close();
path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
path.lineTo(SkIntToScalar(150), SkIntToScalar(50));
path.lineTo(SkIntToScalar(150), SkIntToScalar(125));
path.quadTo(SkIntToScalar(150), SkIntToScalar(150), SkIntToScalar(125), SkIntToScalar(150));
path.lineTo(SkIntToScalar(50), SkIntToScalar(150));
path.close();
path.setFillType(SkPath::kEvenOdd_FillType);
SkColor pathColor = SK_ColorBLACK;
SkPaint pathPaint;
pathPaint.setAntiAlias(true);
pathPaint.setColor(pathColor);
SkPath clipA;
clipA.moveTo(SkIntToScalar(10), SkIntToScalar(20));
clipA.lineTo(SkIntToScalar(165), SkIntToScalar(22));
clipA.lineTo(SkIntToScalar(70), SkIntToScalar(105));
clipA.lineTo(SkIntToScalar(165), SkIntToScalar(177));
clipA.lineTo(SkIntToScalar(-5), SkIntToScalar(180));
clipA.close();
SkColor colorA = SK_ColorCYAN;
SkPath clipB;
clipB.moveTo(SkIntToScalar(40), SkIntToScalar(10));
clipB.lineTo(SkIntToScalar(190), SkIntToScalar(15));
clipB.lineTo(SkIntToScalar(195), SkIntToScalar(190));
clipB.lineTo(SkIntToScalar(40), SkIntToScalar(185));
clipB.lineTo(SkIntToScalar(155), SkIntToScalar(100));
clipB.close();
SkColor colorB = SK_ColorRED;
SkPaint paint;
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(0);
canvas->translate(SkIntToScalar(10),SkIntToScalar(10));
canvas->drawPath(path, pathPaint);
paint.setColor(colorA);
canvas->drawPath(clipA, paint);
paint.setColor(colorB);
canvas->drawPath(clipB, paint);
static const struct {
SkRegion::Op fOp;
const char* fName;
} gOps[] = { //extra spaces in names for measureText
{SkRegion::kIntersect_Op, "Isect "},
{SkRegion::kDifference_Op, "Diff " },
{SkRegion::kUnion_Op, "Union "},
{SkRegion::kXOR_Op, "Xor " },
{SkRegion::kReverseDifference_Op, "RDiff "}
};
canvas->translate(0, SkIntToScalar(40));
canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
canvas->save();
for (int invA = 0; invA < 2; ++invA) {
for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
int idx = invA * SK_ARRAY_COUNT(gOps) + op;
if (!(idx % 3)) {
canvas->restore();
canvas->translate(0, SkIntToScalar(250));
canvas->save();
}
canvas->save();
// set clip
clipA.setFillType(invA ? SkPath::kInverseEvenOdd_FillType :
SkPath::kEvenOdd_FillType);
canvas->clipPath(clipA);
canvas->clipPath(clipB, gOps[op].fOp);
// draw path clipped
canvas->drawPath(path, pathPaint);
canvas->restore();
// draw path in hairline
paint.setColor(pathColor);
canvas->drawPath(path, paint);
// draw clips in hair line
paint.setColor(colorA);
canvas->drawPath(clipA, paint);
paint.setColor(colorB);
canvas->drawPath(clipB, paint);
paint.setTextSize(SkIntToScalar(20));
SkScalar txtX = SkIntToScalar(55);
//.........这里部分代码省略.........
示例15: GR_AUDIT_TRAIL_AUTO_FRAME
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(),
"GrStencilAndCoverPathRenderer::onDrawPath");
SkASSERT(!args.fPaint->isAntiAlias() || args.fDrawContext->isStencilBufferMultisampled());
SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
const SkMatrix& viewMatrix = *args.fViewMatrix;
SkPath path;
args.fShape->asPath(&path);
SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, args.fShape->style()));
if (path.isInverseFillType()) {
SkMatrix invert = SkMatrix::I();
SkRect bounds =
SkRect::MakeLTRB(0, 0,
SkIntToScalar(args.fDrawContext->width()),
SkIntToScalar(args.fDrawContext->height()));
SkMatrix vmi;
// mapRect through persp matrix may not be correct
if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
vmi.mapRect(&bounds);
// theoretically could set bloat = 0, instead leave it because of matrix inversion
// precision.
SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
bounds.outset(bloat, bloat);
} else {
if (!viewMatrix.invert(&invert)) {
return false;
}
}
const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
SkAutoTUnref<GrDrawBatch> coverBatch(
GrRectBatchFactory::CreateNonAAFill(args.fPaint->getColor(), viewM, bounds,
nullptr, &invert));
// fake inverse with a stencil and cover
args.fDrawContext->drawContextPriv().stencilPath(*args.fClip, args.fPaint->isAntiAlias(),
viewMatrix, p);
{
static constexpr GrUserStencilSettings kInvertedCoverPass(
GrUserStencilSettings::StaticInit<
0x0000,
// We know our rect will hit pixels outside the clip and the user bits will
// be 0 outside the clip. So we can't just fill where the user bits are 0. We
// also need to check that the clip bit is set.
GrUserStencilTest::kEqualIfInClip,
0xffff,
GrUserStencilOp::kKeep,
GrUserStencilOp::kZero,
0xffff>()
);
GrPipelineBuilder pipelineBuilder(*args.fPaint,
args.fPaint->isAntiAlias() &&
!args.fDrawContext->hasMixedSamples());
pipelineBuilder.setUserStencil(&kInvertedCoverPass);
args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, coverBatch);
}
} else {
static constexpr GrUserStencilSettings kCoverPass(
GrUserStencilSettings::StaticInit<
0x0000,
GrUserStencilTest::kNotEqual,
0xffff,
GrUserStencilOp::kZero,
GrUserStencilOp::kKeep,
0xffff>()
);
SkAutoTUnref<GrDrawBatch> batch(
GrDrawPathBatch::Create(viewMatrix, args.fPaint->getColor(), p->getFillType(), p));
GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fPaint->isAntiAlias());
pipelineBuilder.setUserStencil(&kCoverPass);
if (args.fAntiAlias) {
SkASSERT(args.fDrawContext->isStencilBufferMultisampled());
pipelineBuilder.enableState(GrPipelineBuilder::kHWAntialias_Flag);
}
args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch);
}
return true;
}