SkRRect.cpp revision 32c1b66a2c4f26935ba59f3afe3e81600fade78d
15985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com/* 25985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com * Copyright 2012 Google Inc. 35985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com * 45985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be 55985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com * found in the LICENSE file. 65985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com */ 75985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 85985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com#include "SkRRect.h" 95985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 105985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com/////////////////////////////////////////////////////////////////////////////// 115985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 125985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comvoid SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { 135985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (rect.isEmpty()) { 145985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com this->setEmpty(); 155985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 165985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (xRad <= 0 || yRad <= 0) { 195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // all corners are square in this case 205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com this->setRect(rect); 215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (rect.width() < xRad+xRad || rect.height() < yRad+yRad) { 255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalar scale = SkMinScalar(SkScalarDiv(rect.width(), xRad + xRad), 265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalarDiv(rect.height(), yRad + yRad)); 275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(scale < SK_Scalar1); 285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com xRad = SkScalarMul(xRad, scale); 295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com yRad = SkScalarMul(yRad, scale); 305985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 325985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRect = rect; 335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com for (int i = 0; i < 4; ++i) { 345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRadii[i].set(xRad, yRad); 355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kSimple_Type; 375985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height())) { 385985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kOval_Type; 395b33211c5edafde82af781beaa1dbc295000a62frobertphillips@google.com // TODO: assert that all the x&y radii are already W/2 & H/2 405985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 425985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkDEBUGCODE(this->validate();) 435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com} 445985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 455985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comvoid SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { 465985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (rect.isEmpty()) { 475985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com this->setEmpty(); 485985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 495985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 505985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 515985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRect = rect; 525985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com memcpy(fRadii, radii, sizeof(fRadii)); 535985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 545985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com bool allCornersSquare = true; 555985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 565985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // Clamp negative radii to zero 575985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com for (int i = 0; i < 4; ++i) { 585985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) { 595985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // In this case we are being a little fast & loose. Since one of 605985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // the radii is 0 the corner is square. However, the other radii 615985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // could still be non-zero and play in the global scale factor 625985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // computation. 635985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRadii[i].fX = 0; 645985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRadii[i].fY = 0; 655985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else { 665985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com allCornersSquare = false; 675985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 685985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 695985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 705985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (allCornersSquare) { 715985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com this->setRect(rect); 725985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 735985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 745985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 755985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // Proportionally scale down all radii to fit. Find the minimum ratio 76c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com // of a side and the radii on that side (for all four sides) and use 775985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // that to scale down _all_ the radii. This algorithm is from the 785985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping 795985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // Curves: 80c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com // "Let f = min(Li/Si), where i is one of { top, right, bottom, left }, 815985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // Si is the sum of the two corresponding radii of the corners on side i, 82c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com // and Ltop = Lbottom = the width of the box, 83c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com // and Lleft = Lright = the height of the box. 845985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // If f < 1, then all corner radii are reduced by multiplying them by f." 855985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalar scale = SK_Scalar1; 865985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 875985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[0].fX + fRadii[1].fX > rect.width()) { 885985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com scale = SkMinScalar(scale, 895985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalarDiv(rect.width(), fRadii[0].fX + fRadii[1].fX)); 905985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 915985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[1].fY + fRadii[2].fY > rect.height()) { 925985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com scale = SkMinScalar(scale, 935985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalarDiv(rect.height(), fRadii[1].fY + fRadii[2].fY)); 945985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 955985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[2].fX + fRadii[3].fX > rect.width()) { 965985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com scale = SkMinScalar(scale, 975985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalarDiv(rect.width(), fRadii[2].fX + fRadii[3].fX)); 985985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 995985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[3].fY + fRadii[0].fY > rect.height()) { 1005985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com scale = SkMinScalar(scale, 1015985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkScalarDiv(rect.height(), fRadii[3].fY + fRadii[0].fY)); 1025985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1035985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1045985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (scale < SK_Scalar1) { 1055985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com for (int i = 0; i < 4; ++i) { 1065985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRadii[i].fX = SkScalarMul(fRadii[i].fX, scale); 1075985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRadii[i].fY = SkScalarMul(fRadii[i].fY, scale); 1085985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1095985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1105985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1115985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // At this point we're either oval, simple, or complex (not empty or rect) 1125985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // but we lazily resolve the type to avoid the work if the information 1135985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // isn't required. 1145985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = (SkRRect::Type) kUnknown_Type; 1155985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1165985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkDEBUGCODE(this->validate();) 1175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com} 1185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.combool SkRRect::contains(SkScalar x, SkScalar y) const { 1205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkDEBUGCODE(this->validate();) 1215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (kEmpty_Type == this->type()) { 1235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return false; 1245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (!fRect.contains(x, y)) { 1275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return false; 1285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1305985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (kRect_Type == this->type()) { 1315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // the 'fRect' test above was sufficient 1325985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return true; 1335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // We know the point is inside the RR's bounds. The only way it can 1365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // be out is if it outside one of the corners 13732c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com return checkCornerContainment(x, y); 13832c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com} 13932c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com 14032c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com// This method determines if a point known to be inside the RRect's bounds is 14132c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com// inside all the corners. 14232c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.combool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { 1435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkPoint canonicalPt; // (x,y) translated to one of the quadrants 1445985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com int index; 1455985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1465985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (kOval_Type == this->type()) { 1475985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com canonicalPt.set(x - fRect.centerX(), y - fRect.centerY()); 1485985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com index = kUpperLeft_Corner; // any corner will do in this case 1495985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else { 150c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com if (x < fRect.fLeft + fRadii[kUpperLeft_Corner].fX && 1515985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y < fRect.fTop + fRadii[kUpperLeft_Corner].fY) { 1525985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // UL corner 1535985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com index = kUpperLeft_Corner; 1545985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com canonicalPt.set(x - (fRect.fLeft + fRadii[kUpperLeft_Corner].fX), 1555985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y - (fRect.fTop + fRadii[kUpperLeft_Corner].fY)); 1565985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY < 0); 1575985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else if (x < fRect.fLeft + fRadii[kLowerLeft_Corner].fX && 1585985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y > fRect.fBottom - fRadii[kLowerLeft_Corner].fY) { 1595985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // LL corner 1605985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com index = kLowerLeft_Corner; 1615985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com canonicalPt.set(x - (fRect.fLeft + fRadii[kLowerLeft_Corner].fX), 1625985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y - (fRect.fBottom - fRadii[kLowerLeft_Corner].fY)); 1635985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY > 0); 1645985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else if (x > fRect.fRight - fRadii[kUpperRight_Corner].fX && 1655985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y < fRect.fTop + fRadii[kUpperRight_Corner].fY) { 1665985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // UR corner 1675985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com index = kUpperRight_Corner; 1685985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com canonicalPt.set(x - (fRect.fRight - fRadii[kUpperRight_Corner].fX), 1695985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y - (fRect.fTop + fRadii[kUpperRight_Corner].fY)); 1705985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY < 0); 1715985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else if (x > fRect.fRight - fRadii[kLowerRight_Corner].fX && 1725985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y > fRect.fBottom - fRadii[kLowerRight_Corner].fY) { 1735985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // LR corner 1745985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com index = kLowerRight_Corner; 1755985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com canonicalPt.set(x - (fRect.fRight - fRadii[kLowerRight_Corner].fX), 1765985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com y - (fRect.fBottom - fRadii[kLowerRight_Corner].fY)); 1775985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY > 0); 1785985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else { 1795985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // not in any of the corners 1805985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return true; 1815985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1825985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 1835985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 1845985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // A point is in an ellipse (in standard position) if: 1855985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // x^2 y^2 1865985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // ----- + ----- <= 1 1875985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // a^2 b^2 18832c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // or : 18932c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // b^2*x^2 + a^2*y^2 <= (ab)^2 19032c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com SkScalar dist = SkScalarMul(SkScalarSquare(canonicalPt.fX), SkScalarSquare(fRadii[index].fY)) + 19132c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com SkScalarMul(SkScalarSquare(canonicalPt.fY), SkScalarSquare(fRadii[index].fX)); 19232c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com return dist <= SkScalarSquare(SkScalarMul(fRadii[index].fX, fRadii[index].fY)); 19332c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com} 19432c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com 19532c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.combool SkRRect::contains(const SkRect& rect) const { 19632c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com if (!this->getBounds().contains(rect)) { 19732c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // If 'rect' isn't contained by the RR's bounds then the 19832c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // RR definitely doesn't contain it 19932c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com return false; 20032c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com } 20132c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com 20232c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com if (this->isRect()) { 20332c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // the prior test was sufficient 20432c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com return true; 20532c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com } 20632c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com 20732c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // At this point we know all four corners of 'rect' are inside the 20832c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // bounds of of this RR. Check to make sure all the corners are inside 20932c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com // all the curves 21032c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com return this->checkCornerContainment(rect.fLeft, rect.fTop) && 21132c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com this->checkCornerContainment(rect.fRight, rect.fTop) && 21232c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com this->checkCornerContainment(rect.fRight, rect.fBottom) && 21332c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com this->checkCornerContainment(rect.fLeft, rect.fBottom); 2145985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com} 2155985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2165985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com// There is a simplified version of this method in setRectXY 2175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comvoid SkRRect::computeType() const { 2185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkDEBUGCODE(this->validate();) 2195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRect.isEmpty()) { 2215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kEmpty_Type; 2225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 2235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com bool allRadiiEqual = true; // are all x radii equal and all y radii? 2265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com bool allCornersSquare = 0 == fRadii[0].fX || 0 == fRadii[0].fY; 2275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com for (int i = 1; i < 4; ++i) { 2295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (0 != fRadii[i].fX && 0 != fRadii[i].fY) { 2305985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // if either radius is zero the corner is square so both have to 2315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // be non-zero to have a rounded corner 2325985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com allCornersSquare = false; 2335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) { 2355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com allRadiiEqual = false; 2365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2375985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2385985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2395985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (allCornersSquare) { 2405985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kRect_Type; 2415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 2425985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2445985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (allRadiiEqual) { 2455985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[0].fX >= SkScalarHalf(fRect.width()) && 2465985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fRadii[0].fY >= SkScalarHalf(fRect.height())) { 2475985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kOval_Type; 2485985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } else { 2495985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kSimple_Type; 2505985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2515985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com return; 2525985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 2535985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2545985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com fType = kComplex_Type; 2555985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com} 2565985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 2574ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com/////////////////////////////////////////////////////////////////////////////// 25837071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org 259bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.orgvoid SkRRect::inset(SkScalar dx, SkScalar dy, SkRRect* dst) const { 26037071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org SkRect r = fRect; 2611a60dab449ee8ab3b4c4330a18fae57b5980363eskia.committer@gmail.com 26237071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org r.inset(dx, dy); 26337071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org if (r.isEmpty()) { 26437071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org dst->setEmpty(); 26537071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org return; 26637071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org } 26737071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org 26837071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org SkVector radii[4]; 269bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org memcpy(radii, fRadii, sizeof(radii)); 27037071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org for (int i = 0; i < 4; ++i) { 271bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org if (radii[i].fX) { 272bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org radii[i].fX -= dx; 273bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org } 274bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org if (radii[i].fY) { 275bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org radii[i].fY -= dy; 276bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org } 27737071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org } 27837071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org dst->setRectRadii(r, radii); 27937071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org} 280bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org 28137071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 28237071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org 2834ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.comuint32_t SkRRect::writeToMemory(void* buffer) const { 2844ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com SkASSERT(kSizeInMemory == sizeof(SkRect) + sizeof(fRadii)); 2854ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 2864ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com memcpy(buffer, &fRect, sizeof(SkRect)); 2874ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com memcpy((char*)buffer + sizeof(SkRect), fRadii, sizeof(fRadii)); 2884ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com return kSizeInMemory; 2894ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com} 2904ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 2914ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.comuint32_t SkRRect::readFromMemory(const void* buffer) { 2924ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com SkScalar storage[12]; 2934ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com SkASSERT(sizeof(storage) == kSizeInMemory); 2944ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 2954ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com // we make a local copy, to ensure alignment before we cast 2964ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com memcpy(storage, buffer, kSizeInMemory); 2974ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 2984ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com this->setRectRadii(*(const SkRect*)&storage[0], 2994ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com (const SkVector*)&storage[4]); 3004ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com return kSizeInMemory; 3014ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com} 3024ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 3034ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com/////////////////////////////////////////////////////////////////////////////// 3044ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 3055985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com#ifdef SK_DEBUG 3065985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comvoid SkRRect::validate() const { 3075985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com bool allRadiiZero = (0 == fRadii[0].fX && 0 == fRadii[0].fY); 3085985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com bool allCornersSquare = (0 == fRadii[0].fX || 0 == fRadii[0].fY); 3095985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com bool allRadiiSame = true; 3105985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 3115985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com for (int i = 1; i < 4; ++i) { 3125985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (0 != fRadii[i].fX || 0 != fRadii[i].fY) { 3135985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com allRadiiZero = false; 3145985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 3155985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 3165985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) { 3175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com allRadiiSame = false; 3185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 3195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 3205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com if (0 != fRadii[i].fX && 0 != fRadii[i].fY) { 3215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com allCornersSquare = false; 3225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 3235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 3245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 3255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com switch (fType) { 3265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com case kEmpty_Type: 3275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(fRect.isEmpty()); 3285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare); 3295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 330c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com SkASSERT(0 == fRect.fLeft && 0 == fRect.fTop && 3315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 0 == fRect.fRight && 0 == fRect.fBottom); 3325985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com break; 3335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com case kRect_Type: 3345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!fRect.isEmpty()); 3355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare); 3365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com break; 3375985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com case kOval_Type: 3385985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!fRect.isEmpty()); 3395985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare); 3405985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 3415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com for (int i = 0; i < 4; ++i) { 3425985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(SkScalarNearlyEqual(fRadii[i].fX, SkScalarHalf(fRect.width()))); 3435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(SkScalarNearlyEqual(fRadii[i].fY, SkScalarHalf(fRect.height()))); 3445985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 3455985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com break; 3465985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com case kSimple_Type: 3475985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!fRect.isEmpty()); 3485985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare); 3495985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com break; 3505985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com case kComplex_Type: 3515985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!fRect.isEmpty()); 3525985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare); 3535985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com break; 3545985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com case kUnknown_Type: 3555985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com // no limits on this 3565985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com break; 3575985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com } 3585985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com} 3595985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com#endif // SK_DEBUG 3605985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com 3615985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com/////////////////////////////////////////////////////////////////////////////// 362