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