void draw(SkCanvas* canvas) { SkRect largest = { SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax }; SkDebugf("largest is finite: %s\n", largest.isFinite() ? "true" : "false"); SkDebugf("large width %g\n", largest.width()); SkRect widest = SkRect::MakeWH(largest.width(), largest.height()); SkDebugf("widest is finite: %s\n", widest.isFinite() ? "true" : "false"); }
void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { if (rect.isEmpty() || !rect.isFinite()) { this->setEmpty(); return; } if (!SkScalarsAreFinite(xRad, yRad)) { xRad = yRad = 0; // devolve into a simple rect } if (xRad <= 0 || yRad <= 0) { // all corners are square in this case this->setRect(rect); return; } if (rect.width() < xRad+xRad || rect.height() < yRad+yRad) { SkScalar scale = SkMinScalar(rect.width() / (xRad + xRad), rect.height() / (yRad + yRad)); SkASSERT(scale < SK_Scalar1); xRad = SkScalarMul(xRad, scale); yRad = SkScalarMul(yRad, scale); } fRect = rect; for (int i = 0; i < 4; ++i) { fRadii[i].set(xRad, yRad); } fType = kSimple_Type; if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height())) { fType = kOval_Type; // TODO: assert that all the x&y radii are already W/2 & H/2 } SkDEBUGCODE(this->validate();) }
void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad) { if (rect.isEmpty() || !rect.isFinite()) { this->setEmpty(); return; } const SkScalar array[4] = { leftRad, topRad, rightRad, bottomRad }; if (!SkScalarsAreFinite(array, 4)) { this->setRect(rect); // devolve into a simple rect return; } leftRad = SkMaxScalar(leftRad, 0); topRad = SkMaxScalar(topRad, 0); rightRad = SkMaxScalar(rightRad, 0); bottomRad = SkMaxScalar(bottomRad, 0); SkScalar scale = SK_Scalar1; if (leftRad + rightRad > rect.width()) { scale = rect.width() / (leftRad + rightRad); } if (topRad + bottomRad > rect.height()) { scale = SkMinScalar(scale, rect.height() / (topRad + bottomRad)); } if (scale < SK_Scalar1) { leftRad = SkScalarMul(leftRad, scale); topRad = SkScalarMul(topRad, scale); rightRad = SkScalarMul(rightRad, scale); bottomRad = SkScalarMul(bottomRad, scale); } if (leftRad == rightRad && topRad == bottomRad) { if (leftRad >= SkScalarHalf(rect.width()) && topRad >= SkScalarHalf(rect.height())) { fType = kOval_Type; } else if (0 == leftRad || 0 == topRad) { // If the left and (by equality check above) right radii are zero then it is a rect. // Same goes for top/bottom. fType = kRect_Type; leftRad = 0; topRad = 0; rightRad = 0; bottomRad = 0; } else { fType = kSimple_Type; } } else { fType = kNinePatch_Type; } fRect = rect; fRadii[kUpperLeft_Corner].set(leftRad, topRad); fRadii[kUpperRight_Corner].set(rightRad, topRad); fRadii[kLowerRight_Corner].set(rightRad, bottomRad); fRadii[kLowerLeft_Corner].set(leftRad, bottomRad); SkDEBUGCODE(this->validate();) }
void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { if (rect.isEmpty() || !rect.isFinite()) { this->setEmpty(); return; } if (!SkScalarsAreFinite(&radii[0].fX, 8)) { this->setRect(rect); // devolve into a simple rect return; } fRect = rect; memcpy(fRadii, radii, sizeof(fRadii)); bool allCornersSquare = true; // Clamp negative radii to zero for (int i = 0; i < 4; ++i) { if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) { // In this case we are being a little fast & loose. Since one of // the radii is 0 the corner is square. However, the other radii // could still be non-zero and play in the global scale factor // computation. fRadii[i].fX = 0; fRadii[i].fY = 0; } else { allCornersSquare = false; } } if (allCornersSquare) { this->setRect(rect); return; } // Proportionally scale down all radii to fit. Find the minimum ratio // of a side and the radii on that side (for all four sides) and use // that to scale down _all_ the radii. This algorithm is from the // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping // Curves: // "Let f = min(Li/Si), where i is one of { top, right, bottom, left }, // Si is the sum of the two corresponding radii of the corners on side i, // and Ltop = Lbottom = the width of the box, // and Lleft = Lright = the height of the box. // If f < 1, then all corner radii are reduced by multiplying them by f." double scale = 1.0; scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, rect.width(), scale); scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, rect.height(), scale); scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, rect.width(), scale); scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, rect.height(), scale); if (scale < 1.0) { for (int i = 0; i < 4; ++i) { fRadii[i].fX *= scale; fRadii[i].fY *= scale; } } // skbug.com/3239 -- its possible that we can hit the following inconsistency: // rad == bounds.bottom - bounds.top // bounds.bottom - radius < bounds.top // YIKES // We need to detect and "fix" this now, otherwise we can have the following wackiness: // path.addRRect(rrect); // rrect.rect() != path.getBounds() for (int i = 0; i < 4; ++i) { fRadii[i].fX = clamp_radius_check_predicates(fRadii[i].fX, rect.fLeft, rect.fRight); fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, rect.fTop, rect.fBottom); } // At this point we're either oval, simple, or complex (not empty or rect). this->computeType(); SkDEBUGCODE(this->validate();) }