void SkRRect::scaleRadii() { // 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; // The sides of the rectangle may be larger than a float. double width = (double)fRect.fRight - (double)fRect.fLeft; double height = (double)fRect.fBottom - (double)fRect.fTop; scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, width, scale); scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, height, scale); scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, width, scale); scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, height, scale); if (scale < 1.0) { SkScaleToSides::AdjustRadii(width, scale, &fRadii[0].fX, &fRadii[1].fX); SkScaleToSides::AdjustRadii(height, scale, &fRadii[1].fY, &fRadii[2].fY); SkScaleToSides::AdjustRadii(width, scale, &fRadii[2].fX, &fRadii[3].fX); SkScaleToSides::AdjustRadii(height, scale, &fRadii[3].fY, &fRadii[0].fY); } // At this point we're either oval, simple, or complex (not empty or rect). this->computeType(); SkDEBUGCODE(this->validate();) }
void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { fRect = rect; fRect.sort(); if (fRect.isEmpty() || !fRect.isFinite()) { this->setEmpty(); return; } if (!SkScalarsAreFinite(&radii[0].fX, 8)) { this->setRect(rect); // devolve into a simple rect return; } 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, fRect.width(), scale); scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, fRect.height(), scale); scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, fRect.width(), scale); scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, fRect.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, fRect.fLeft, fRect.fRight); fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom); } // At this point we're either oval, simple, or complex (not empty or rect). this->computeType(); SkDEBUGCODE(this->validate();) }