1363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/* 2363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Copyright 2012 Google Inc. 3363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * 4363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Use of this source code is governed by a BSD-style license that can be 5363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * found in the LICENSE file. 6363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger */ 7363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 8363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkRRect.h" 9363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 10363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/////////////////////////////////////////////////////////////////////////////// 11363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 12363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { 13363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (rect.isEmpty()) { 14363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->setEmpty(); 15363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 16363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 17363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 18363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (xRad <= 0 || yRad <= 0) { 19363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // all corners are square in this case 20363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->setRect(rect); 21363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 22363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 23363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 24363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (rect.width() < xRad+xRad || rect.height() < yRad+yRad) { 25363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalar scale = SkMinScalar(SkScalarDiv(rect.width(), xRad + xRad), 26363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalarDiv(rect.height(), yRad + yRad)); 27363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(scale < SK_Scalar1); 28363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger xRad = SkScalarMul(xRad, scale); 29363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger yRad = SkScalarMul(yRad, scale); 30363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 31363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 32363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRect = rect; 33363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < 4; ++i) { 34363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRadii[i].set(xRad, yRad); 35363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 36363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kSimple_Type; 37363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height())) { 38363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kOval_Type; 39d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger // TODO: assert that all the x&y radii are already W/2 & H/2 40363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 41363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 42363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGCODE(this->validate();) 43363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 44363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 45363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { 46363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (rect.isEmpty()) { 47363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->setEmpty(); 48363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 49363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 50363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 51363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRect = rect; 52363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger memcpy(fRadii, radii, sizeof(fRadii)); 53363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 54363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool allCornersSquare = true; 55363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 56363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Clamp negative radii to zero 57363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < 4; ++i) { 58363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) { 59363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // In this case we are being a little fast & loose. Since one of 60363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // the radii is 0 the corner is square. However, the other radii 61363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // could still be non-zero and play in the global scale factor 62363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // computation. 63363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRadii[i].fX = 0; 64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRadii[i].fY = 0; 65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 66363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger allCornersSquare = false; 67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 68363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 69363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 70363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (allCornersSquare) { 71363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->setRect(rect); 72363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 73363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Proportionally scale down all radii to fit. Find the minimum ratio 76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // of a side and the radii on that side (for all four sides) and use 77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // that to scale down _all_ the radii. This algorithm is from the 78363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping 79363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Curves: 80363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // "Let f = min(Li/Si), where i is one of { top, right, bottom, left }, 81363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Si is the sum of the two corresponding radii of the corners on side i, 82363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // and Ltop = Lbottom = the width of the box, 83363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // and Lleft = Lright = the height of the box. 84363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // If f < 1, then all corner radii are reduced by multiplying them by f." 85363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalar scale = SK_Scalar1; 86363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 87363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[0].fX + fRadii[1].fX > rect.width()) { 88363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger scale = SkMinScalar(scale, 89363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalarDiv(rect.width(), fRadii[0].fX + fRadii[1].fX)); 90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 91363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[1].fY + fRadii[2].fY > rect.height()) { 92363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger scale = SkMinScalar(scale, 93363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalarDiv(rect.height(), fRadii[1].fY + fRadii[2].fY)); 94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[2].fX + fRadii[3].fX > rect.width()) { 96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger scale = SkMinScalar(scale, 97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalarDiv(rect.width(), fRadii[2].fX + fRadii[3].fX)); 98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[3].fY + fRadii[0].fY > rect.height()) { 100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger scale = SkMinScalar(scale, 101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalarDiv(rect.height(), fRadii[3].fY + fRadii[0].fY)); 102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (scale < SK_Scalar1) { 105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < 4; ++i) { 106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRadii[i].fX = SkScalarMul(fRadii[i].fX, scale); 107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRadii[i].fY = SkScalarMul(fRadii[i].fY, scale); 108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 109363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 110363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 111363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // At this point we're either oval, simple, or complex (not empty or rect) 112363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // but we lazily resolve the type to avoid the work if the information 113363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // isn't required. 114363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = (SkRRect::Type) kUnknown_Type; 115363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 116363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGCODE(this->validate();) 117363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 118363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 119363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerbool SkRRect::contains(SkScalar x, SkScalar y) const { 120363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGCODE(this->validate();) 121363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 122363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (kEmpty_Type == this->type()) { 123363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return false; 124363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 125363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 126363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!fRect.contains(x, y)) { 127363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return false; 128363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 129363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 130363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (kRect_Type == this->type()) { 131363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // the 'fRect' test above was sufficient 132363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return true; 133363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 134363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 135363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // We know the point is inside the RR's bounds. The only way it can 136363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // be out is if it outside one of the corners 137363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkPoint canonicalPt; // (x,y) translated to one of the quadrants 138363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int index; 139363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 140363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (kOval_Type == this->type()) { 141363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger canonicalPt.set(x - fRect.centerX(), y - fRect.centerY()); 142363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger index = kUpperLeft_Corner; // any corner will do in this case 143363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 144363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (x < fRect.fLeft + fRadii[kUpperLeft_Corner].fX && 145363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y < fRect.fTop + fRadii[kUpperLeft_Corner].fY) { 146363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // UL corner 147363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger index = kUpperLeft_Corner; 148363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger canonicalPt.set(x - (fRect.fLeft + fRadii[kUpperLeft_Corner].fX), 149363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y - (fRect.fTop + fRadii[kUpperLeft_Corner].fY)); 150363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY < 0); 151363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else if (x < fRect.fLeft + fRadii[kLowerLeft_Corner].fX && 152363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y > fRect.fBottom - fRadii[kLowerLeft_Corner].fY) { 153363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // LL corner 154363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger index = kLowerLeft_Corner; 155363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger canonicalPt.set(x - (fRect.fLeft + fRadii[kLowerLeft_Corner].fX), 156363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y - (fRect.fBottom - fRadii[kLowerLeft_Corner].fY)); 157363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY > 0); 158363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else if (x > fRect.fRight - fRadii[kUpperRight_Corner].fX && 159363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y < fRect.fTop + fRadii[kUpperRight_Corner].fY) { 160363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // UR corner 161363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger index = kUpperRight_Corner; 162363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger canonicalPt.set(x - (fRect.fRight - fRadii[kUpperRight_Corner].fX), 163363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y - (fRect.fTop + fRadii[kUpperRight_Corner].fY)); 164363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY < 0); 165363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else if (x > fRect.fRight - fRadii[kLowerRight_Corner].fX && 166363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y > fRect.fBottom - fRadii[kLowerRight_Corner].fY) { 167363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // LR corner 168363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger index = kLowerRight_Corner; 169363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger canonicalPt.set(x - (fRect.fRight - fRadii[kLowerRight_Corner].fX), 170363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger y - (fRect.fBottom - fRadii[kLowerRight_Corner].fY)); 171363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY > 0); 172363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 173363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // not in any of the corners 174363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return true; 175363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 176363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 177363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 178363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // A point is in an ellipse (in standard position) if: 179363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // x^2 y^2 180363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // ----- + ----- <= 1 181363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // a^2 b^2 182363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalar dist = SkScalarDiv(SkScalarSquare(canonicalPt.fX), SkScalarSquare(fRadii[index].fX)) + 183363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalarDiv(SkScalarSquare(canonicalPt.fY), SkScalarSquare(fRadii[index].fY)); 184363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return dist <= SK_Scalar1; 185363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 186363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 187363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger// There is a simplified version of this method in setRectXY 188363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkRRect::computeType() const { 189363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDEBUGCODE(this->validate();) 190363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 191363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRect.isEmpty()) { 192363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kEmpty_Type; 193363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 194363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 195363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 196363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool allRadiiEqual = true; // are all x radii equal and all y radii? 197363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool allCornersSquare = 0 == fRadii[0].fX || 0 == fRadii[0].fY; 198363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 199363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 1; i < 4; ++i) { 200363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (0 != fRadii[i].fX && 0 != fRadii[i].fY) { 201363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // if either radius is zero the corner is square so both have to 202363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // be non-zero to have a rounded corner 203363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger allCornersSquare = false; 204363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 205363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) { 206363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger allRadiiEqual = false; 207363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 208363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 209363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 210363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (allCornersSquare) { 211363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kRect_Type; 212363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 213363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 214363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 215363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (allRadiiEqual) { 216363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[0].fX >= SkScalarHalf(fRect.width()) && 217363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fRadii[0].fY >= SkScalarHalf(fRect.height())) { 218363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kOval_Type; 219363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 220363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kSimple_Type; 221363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 222363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 223363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 224363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 225363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fType = kComplex_Type; 226363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 227363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 228363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/////////////////////////////////////////////////////////////////////////////// 229363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 230d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergervoid SkRRect::inset(SkScalar dx, SkScalar dy, SkRRect* dst) const { 231363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkRect r = fRect; 232d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 233363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger r.inset(dx, dy); 234363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (r.isEmpty()) { 235363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dst->setEmpty(); 236363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 237363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 238363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 239363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkVector radii[4]; 240d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger memcpy(radii, fRadii, sizeof(radii)); 241363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < 4; ++i) { 242d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger if (radii[i].fX) { 243d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger radii[i].fX -= dx; 244d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 245d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger if (radii[i].fY) { 246d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger radii[i].fY -= dy; 247d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 248363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 249363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dst->setRectRadii(r, radii); 250363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 251d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 252363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/////////////////////////////////////////////////////////////////////////////// 253363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 254363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergeruint32_t SkRRect::writeToMemory(void* buffer) const { 255363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(kSizeInMemory == sizeof(SkRect) + sizeof(fRadii)); 256363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 257363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger memcpy(buffer, &fRect, sizeof(SkRect)); 258363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger memcpy((char*)buffer + sizeof(SkRect), fRadii, sizeof(fRadii)); 259363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return kSizeInMemory; 260363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 261363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 262363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergeruint32_t SkRRect::readFromMemory(const void* buffer) { 263363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkScalar storage[12]; 264363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(sizeof(storage) == kSizeInMemory); 265363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 266363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // we make a local copy, to ensure alignment before we cast 267363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger memcpy(storage, buffer, kSizeInMemory); 268363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 269363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->setRectRadii(*(const SkRect*)&storage[0], 270363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger (const SkVector*)&storage[4]); 271363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return kSizeInMemory; 272363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 273363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 274363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/////////////////////////////////////////////////////////////////////////////// 275363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 276363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#ifdef SK_DEBUG 277363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid SkRRect::validate() const { 278363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool allRadiiZero = (0 == fRadii[0].fX && 0 == fRadii[0].fY); 279363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool allCornersSquare = (0 == fRadii[0].fX || 0 == fRadii[0].fY); 280363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool allRadiiSame = true; 281363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 282363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 1; i < 4; ++i) { 283363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (0 != fRadii[i].fX || 0 != fRadii[i].fY) { 284363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger allRadiiZero = false; 285363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 286363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 287363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) { 288363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger allRadiiSame = false; 289363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 290363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 291363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (0 != fRadii[i].fX && 0 != fRadii[i].fY) { 292363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger allCornersSquare = false; 293363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 294363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 295363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 296363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger switch (fType) { 297363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case kEmpty_Type: 298363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(fRect.isEmpty()); 299363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare); 300363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 301363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(0 == fRect.fLeft && 0 == fRect.fTop && 302363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 0 == fRect.fRight && 0 == fRect.fBottom); 303363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 304363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case kRect_Type: 305363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!fRect.isEmpty()); 306363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare); 307363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 308363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case kOval_Type: 309363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!fRect.isEmpty()); 310363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare); 311363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 312363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < 4; ++i) { 313363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(SkScalarNearlyEqual(fRadii[i].fX, SkScalarHalf(fRect.width()))); 314363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(SkScalarNearlyEqual(fRadii[i].fY, SkScalarHalf(fRect.height()))); 315363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 316363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 317363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case kSimple_Type: 318363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!fRect.isEmpty()); 319363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare); 320363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 321363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case kComplex_Type: 322363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!fRect.isEmpty()); 323363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare); 324363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 325363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case kUnknown_Type: 326363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // no limits on this 327363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 328363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 329363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 330363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#endif // SK_DEBUG 331363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 332363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/////////////////////////////////////////////////////////////////////////////// 333