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