bool PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, const Point &aPoint, const Matrix &aTransform) const { Matrix inverse = aTransform; inverse.Invert(); Point transformed = inverse * aPoint; SkPaint paint; StrokeOptionsToPaint(paint, aStrokeOptions); SkPath strokePath; paint.getFillPath(mPath, &strokePath); Rect bounds = aTransform.TransformBounds(SkRectToRect(strokePath.getBounds())); if (aPoint.x < bounds.x || aPoint.y < bounds.y || aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) { return false; } SkRegion pointRect; pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)), int32_t(SkFloatToScalar(transformed.y - 1.f)), int32_t(SkFloatToScalar(transformed.x + 1.f)), int32_t(SkFloatToScalar(transformed.y + 1.f))); SkRegion pathRegion; return pathRegion.setPath(strokePath, pointRect); }
bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) { if (!fMatrixIsInvertible) { return false; } SkPath tmp; SkIRect ir; src.transform(fInverse, &tmp); tmp.getBounds().round(&ir); if (!ir.isEmpty()) { this->begin(ir, dst); SkRegion rgn; rgn.setPath(tmp, SkRegion(ir)); SkRegion::Iterator iter(rgn); for (; !iter.done(); iter.next()) { const SkIRect& rect = iter.rect(); for (int y = rect.fTop; y < rect.fBottom; ++y) { this->nextSpan(rect.fLeft, y, rect.width(), dst); } } this->end(dst); } return true; }
bool SkHitTestPath(const SkPath& path, SkRect& target, bool hires) { if (target.isEmpty()) { return false; } bool isInverse = path.isInverseFillType(); if (path.isEmpty()) { return isInverse; } SkRect bounds = path.getBounds(); bool sects = SkRect::Intersects(target, bounds); if (isInverse) { if (!sects) { return true; } } else { if (!sects) { return false; } if (target.contains(bounds)) { return true; } } SkPath devPath; const SkPath* pathPtr; SkRect devTarget; if (hires) { const SkScalar coordLimit = SkIntToScalar(16384); const SkRect limit = { 0, 0, coordLimit, coordLimit }; SkMatrix matrix; matrix.setRectToRect(bounds, limit, SkMatrix::kFill_ScaleToFit); path.transform(matrix, &devPath); matrix.mapRect(&devTarget, target); pathPtr = &devPath; } else { devTarget = target; pathPtr = &path; } SkIRect iTarget; devTarget.round(&iTarget); if (iTarget.isEmpty()) { iTarget.fLeft = SkScalarFloorToInt(devTarget.fLeft); iTarget.fTop = SkScalarFloorToInt(devTarget.fTop); iTarget.fRight = iTarget.fLeft + 1; iTarget.fBottom = iTarget.fTop + 1; } SkRegion clip(iTarget); SkRegion rgn; return rgn.setPath(*pathPtr, clip) ^ isInverse; }
static jboolean Region_setPath(JNIEnv* env, jobject, jlong dstHandle, jlong pathHandle, jlong clipHandle) { SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); const SkRegion* clip = reinterpret_cast<SkRegion*>(clipHandle); SkASSERT(dst && path && clip); bool result = dst->setPath(*path, *clip); return boolTojboolean(result); }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; SkRect bounds; // FIXME: This #ifdef can go away once we're firmly using the new Skia. // During the transition, this makes the code compatible with both versions. #ifdef SK_USE_OLD_255_TO_256 bounds = originalPath->getBounds(); #else originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType); #endif // We can immediately return false if the point is outside the bounding rect if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) return false; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); clip.setRect(x, y, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; }
static bool test_pathregion() { SkPath path; SkRegion region; path.moveTo(25071800.f, -141823808.f); path.lineTo(25075500.f, -141824000.f); path.lineTo(25075400.f, -141827712.f); path.lineTo(25071810.f, -141827600.f); path.close(); SkIRect bounds; path.getBounds().round(&bounds); SkRegion clip(bounds); return region.setPath(path, clip); // <-- !! DOWN !! }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; SkRect bounds = originalPath->getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; }
static void test_pathregion() { SkPath path; SkRegion region; path.moveTo(25071800.f, -141823808.f); path.lineTo(25075500.f, -141824000.f); path.lineTo(25075400.f, -141827712.f); path.lineTo(25071810.f, -141827600.f); path.close(); SkIRect bounds; path.getBounds().round(&bounds); SkRegion clip(bounds); bool result = region.setPath(path, clip); // <-- !! DOWN !! SkDebugf("----- result %d\n", result); }
bool SkPathContainsPoint(const SkPath& originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath.getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; // Scale the path to a large size before hit testing for two reasons: // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. // TODO: when Skia is patched to work properly with large values, this will not be necessary. // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. // 3) Scale the x/y axis separately so an extreme large/small scale factor on one axis won't // ruin the resolution of the other axis. SkScalar biggestCoordX = std::max(bounds.fRight, -bounds.fLeft); SkScalar biggestCoordY = std::max(bounds.fBottom, -bounds.fTop); if (SkScalarNearlyZero(biggestCoordX) || SkScalarNearlyZero(biggestCoordY)) return false; biggestCoordX = std::max(biggestCoordX, std::fabs(fX) + 1); biggestCoordY = std::max(biggestCoordY, std::fabs(fY) + 1); const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); SkScalar scaleX = kMaxCoordinate / biggestCoordX; SkScalar scaleY = kMaxCoordinate / biggestCoordY; SkRegion rgn; SkRegion clip; SkMatrix m; SkPath scaledPath(originalPath); scaledPath.setFillType(ft); m.setScale(scaleX, scaleY); scaledPath.transform(m, 0); int x = static_cast<int>(floorf(0.5f + point.x() * scaleX)); int y = static_cast<int>(floorf(0.5f + point.y() * scaleY)); clip.setRect(x - 1, y - 1, x + 1, y + 1); return rgn.setPath(scaledPath, clip); }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath->getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; // Scale the path to a large size before hit testing for two reasons: // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. // TODO: when Skia is patched to work properly with large values, this will not be necessary. // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (SkScalarNearlyZero(biggestCoord)) return false; biggestCoord = std::max(std::max(biggestCoord, fX + 1), fY + 1); const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); SkScalar scale = SkScalarDiv(kMaxCoordinate, biggestCoord); SkRegion rgn; SkRegion clip; SkMatrix m; SkPath scaledPath; SkPath::FillType originalFillType = originalPath->getFillType(); originalPath->setFillType(ft); m.setScale(scale, scale); originalPath->transform(m, &scaledPath); int x = static_cast<int>(floorf(0.5f + point.x() * scale)); int y = static_cast<int>(floorf(0.5f + point.y() * scale)); clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(scaledPath, clip); originalPath->setFillType(originalFillType); return contains; }
bool PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const { Matrix inverse = aTransform; inverse.Invert(); Point transformed = inverse * aPoint; Rect bounds = GetBounds(aTransform); if (aPoint.x < bounds.x || aPoint.y < bounds.y || aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) { return false; } SkRegion pointRect; pointRect.setRect(SkFloatToScalar(transformed.x - 1), SkFloatToScalar(transformed.y - 1), SkFloatToScalar(transformed.x + 1), SkFloatToScalar(transformed.y + 1)); SkRegion pathRegion; return pathRegion.setPath(mPath, pointRect); }