static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc) { #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA SkPoint topleft = {rc.fLeft, rc.fTop}; SkPoint bottomright = {rc.fRight, rc.fBottom}; return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright); #else return true; #endif }
// This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { if (paintingDisabled()) return; StrokeStyle penStyle = strokeStyle(); if (penStyle == NoStroke) return; SkPaint paint; if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2)) return; platformContext()->prepareForSoftwareDraw(); FloatPoint p1 = point1; FloatPoint p2 = point2; bool isVerticalLine = (p1.x() == p2.x()); int width = roundf(strokeThickness()); // We know these are vertical or horizontal lines, so the length will just // be the sum of the displacement component vectors give or take 1 - // probably worth the speed up of no square root, which also won't be exact. FloatSize disp = p2 - p1; int length = SkScalarRound(disp.width() + disp.height()); platformContext()->setupPaintForStroking(&paint, 0, length); if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. SkRect r1, r2; r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width); r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width); if (isVerticalLine) { r1.offset(-width / 2, 0); r2.offset(-width / 2, -width); } else { r1.offset(0, -width / 2); r2.offset(-width, -width / 2); } SkPaint fillPaint; fillPaint.setColor(paint.getColor()); platformContext()->canvas()->drawRect(r1, fillPaint); platformContext()->canvas()->drawRect(r2, fillPaint); } adjustLineToPixelBoundaries(p1, p2, width, penStyle); SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); }
// This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { if (paintingDisabled()) return; StrokeStyle penStyle = strokeStyle(); if (penStyle == NoStroke) return; SkPaint paint; SkPoint pts[2] = { (SkPoint)point1, (SkPoint)point2 }; if (!isPointSkiaSafe(getCTM(), pts[0]) || !isPointSkiaSafe(getCTM(), pts[1])) return; // We know these are vertical or horizontal lines, so the length will just // be the sum of the displacement component vectors give or take 1 - // probably worth the speed up of no square root, which also won't be exact. SkPoint disp = pts[1] - pts[0]; int length = SkScalarRound(disp.fX + disp.fY); int width = roundf( platformContext()->setupPaintForStroking(&paint, 0, length)); // "Borrowed" this comment and idea from GraphicsContextCG.cpp // For odd widths, we add in 0.5 to the appropriate x/y so that the float // arithmetic works out. For example, with a border width of 3, KHTML will // pass us (y1+y2)/2, e.g., (50+53)/2 = 103/2 = 51 when we want 51.5. It is // always true that an even width gave us a perfect position, but an odd // width gave us a position that is off by exactly 0.5. bool isVerticalLine = pts[0].fX == pts[1].fX; if (width & 1) { // Odd. if (isVerticalLine) { pts[0].fX = pts[0].fX + SK_ScalarHalf; pts[1].fX = pts[0].fX; } else { // Horizontal line pts[0].fY = pts[0].fY + SK_ScalarHalf; pts[1].fY = pts[0].fY; } } platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); }
bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path) { #ifdef ENSURE_VALUE_SAFETY_FOR_SKIA SkPoint current_points[4]; SkPath::Iter iter(path, false); for (SkPath::Verb verb = iter.next(current_points); verb != SkPath::kDone_Verb; verb = iter.next(current_points)) { switch (verb) { case SkPath::kMove_Verb: // This move will be duplicated in the next verb, so we can ignore. break; case SkPath::kLine_Verb: // iter.next returns 2 points. if (!isPointSkiaSafe(transform, current_points[0]) || !isPointSkiaSafe(transform, current_points[1])) return false; break; case SkPath::kQuad_Verb: // iter.next returns 3 points. if (!isPointSkiaSafe(transform, current_points[0]) || !isPointSkiaSafe(transform, current_points[1]) || !isPointSkiaSafe(transform, current_points[2])) return false; break; case SkPath::kCubic_Verb: // iter.next returns 4 points. if (!isPointSkiaSafe(transform, current_points[0]) || !isPointSkiaSafe(transform, current_points[1]) || !isPointSkiaSafe(transform, current_points[2]) || !isPointSkiaSafe(transform, current_points[3])) return false; break; case SkPath::kClose_Verb: case SkPath::kDone_Verb: default: break; } } return true; #else return true; #endif }