SkRRect.h revision 5a70bc7f3cd32aaccc137c7d650cea613baa2443
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#ifndef SkRRect_DEFINED
95985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com#define SkRRect_DEFINED
105985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
115985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com#include "SkRect.h"
125985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com#include "SkPoint.h"
135985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
144ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.comclass SkPath;
1520e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.comclass SkMatrix;
164ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com// Path forward:
185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   core work
195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add validate method (all radii positive, all radii sums < rect size, etc.)
205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add contains(SkRect&)  - for clip stack
215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add contains(SkRRect&) - for clip stack
225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add heart rect computation (max rect inside RR)
235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add 9patch rect computation
245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add growToInclude(SkPath&)
255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   analysis
265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      use growToInclude to fit skp round rects & generate stats (RRs vs. real paths)
275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      check on # of rectorus's the RRs could handle
285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   rendering work
2914e50ae2a1b1cccdace599247b8c788b8db33ef4commit-bot@chromium.org//      update SkPath.addRRect() to only use quads
305985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add GM and bench
315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   further out
325985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      detect and triangulate RRectorii rather than falling back to SW in Ganesh
33c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com//
345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com/** \class SkRRect
365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
37c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    The SkRRect class represents a rounded rect with a potentially different
38c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    radii for each corner. It does not have a constructor so must be
39c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    initialized with one of the initialization functions (e.g., setEmpty,
405985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    setRectRadii, etc.)
415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
42c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    This class is intended to roughly match CSS' border-*-*-radius capabilities.
435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    This means:
44c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        If either of a corner's radii are 0 the corner will be square.
455985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        Negative radii are not allowed (they are clamped to zero).
465985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        If the corner curves overlap they will be proportionally reduced to fit.
475985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com*/
485985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comclass SK_API SkRRect {
495985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.compublic:
50c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
515985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Enum to capture the various possible subtypes of RR. Accessed
525985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * by type(). The subtypes become progressively less restrictive.
535985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
545985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    enum Type {
555985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        // !< The RR is empty
565985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kEmpty_Type,
575985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
585985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< The RR is actually a (non-empty) rect (i.e., at least one radius
595985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< at each corner is zero)
60c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        kRect_Type,
615985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
62c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        //!< The RR is actually a (non-empty) oval (i.e., all x radii are equal
635985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< and >= width/2 and all the y radii are equal and >= height/2
64c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        kOval_Type,
655985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
66c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        //!< The RR is non-empty and all the x radii are equal & all y radii
67c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        //!< are equal but it is not an oval (i.e., there are lines between
685985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< the curves) nor a rect (i.e., both radii are non-zero)
69c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        kSimple_Type,
705985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
71f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< The RR is non-empty and the two left x radii are equal, the two top
72f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< y radii are equal, and the same for the right and bottom but it is
73f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< neither an rect, oval, nor a simple RR. It is called "nine patch"
74f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< because the centers of the corner ellipses form an axis aligned
75f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< rect with edges that divide the RR into an 9 rectangular patches:
76f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< an interior patch, four edge patches, and four corner patches.
77f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        kNinePatch_Type,
78f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org
795985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< A fully general (non-empty) RR. Some of the x and/or y radii are
805985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< different from the others and there must be one corner where
815985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< both radii are non-zero.
825985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kComplex_Type,
835985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    };
845985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
85c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
865985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Returns the RR's sub type.
875985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
884ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    Type getType() const {
895985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        SkDEBUGCODE(this->validate();)
90727b8c1d1c0ba0634a97bff601e7af96bfd7daf8reed        return static_cast<Type>(fType);
915985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
925985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
934ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    Type type() const { return this->getType(); }
944ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
954ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isEmpty() const { return kEmpty_Type == this->getType(); }
964ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isRect() const { return kRect_Type == this->getType(); }
974ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isOval() const { return kOval_Type == this->getType(); }
984ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isSimple() const { return kSimple_Type == this->getType(); }
9930c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    // TODO: should isSimpleCircular & isCircle take a tolerance? This could help
10030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    // instances where the mapping to device space is noisy.
101c2f7824436d05da6e8514d06a54773538aace028commit-bot@chromium.org    inline bool isSimpleCircular() const {
10230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        return this->isSimple() && SkScalarNearlyEqual(fRadii[0].fX, fRadii[0].fY);
10330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    }
10430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    inline bool isCircle() const {
10530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        return this->isOval() && SkScalarNearlyEqual(fRadii[0].fX, fRadii[0].fY);
106c2f7824436d05da6e8514d06a54773538aace028commit-bot@chromium.org    }
107f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org    inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); }
1084ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isComplex() const { return kComplex_Type == this->getType(); }
1094ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
110821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org    bool allCornersCircular() const;
111821397018fdabea6b434ecb96f84fb5449c4025fcommit-bot@chromium.org
11237071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    SkScalar width() const { return fRect.width(); }
11337071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    SkScalar height() const { return fRect.height(); }
11437071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org
115c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1165985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Set this RR to the empty rectangle (0,0,0,0) with 0 x & y radii.
1175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
118c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    void setEmpty() {
1195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        fRect.setEmpty();
1205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        memset(fRadii, 0, sizeof(fRadii));
1215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        fType = kEmpty_Type;
1225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        SkDEBUGCODE(this->validate();)
1245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
1255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
126c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Set this RR to match the supplied rect. All radii will be 0.
1285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setRect(const SkRect& rect) {
13005302f8f24cf0254e1fa713fbfc766387505e511robertphillips        fRect = rect;
13105302f8f24cf0254e1fa713fbfc766387505e511robertphillips        fRect.sort();
13205302f8f24cf0254e1fa713fbfc766387505e511robertphillips
13305302f8f24cf0254e1fa713fbfc766387505e511robertphillips        if (fRect.isEmpty()) {
1345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            this->setEmpty();
1355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            return;
1365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        }
1375985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1385985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        memset(fRadii, 0, sizeof(fRadii));
1395985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        fType = kRect_Type;
1405985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        SkDEBUGCODE(this->validate();)
1425985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
1435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
144021f631dc66da06dbe4aed21df2f27daecce9db7reed    static SkRRect MakeRect(const SkRect& r) {
145021f631dc66da06dbe4aed21df2f27daecce9db7reed        SkRRect rr;
146021f631dc66da06dbe4aed21df2f27daecce9db7reed        rr.setRect(r);
147021f631dc66da06dbe4aed21df2f27daecce9db7reed        return rr;
148021f631dc66da06dbe4aed21df2f27daecce9db7reed    }
149021f631dc66da06dbe4aed21df2f27daecce9db7reed
15030c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    static SkRRect MakeOval(const SkRect& oval) {
15130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        SkRRect rr;
15230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        rr.setOval(oval);
15330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        return rr;
15430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    }
15530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
1564a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon    static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) {
1574a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon        SkRRect rr;
1584a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon        rr.setRectXY(rect, xRad, yRad);
1594a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon        return rr;
1604a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon    }
1614a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon
162c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1635985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Set this RR to match the supplied oval. All x radii will equal half the
1645985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * width and all y radii will equal half the height.
1655985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1665985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setOval(const SkRect& oval) {
16705302f8f24cf0254e1fa713fbfc766387505e511robertphillips        fRect = oval;
16805302f8f24cf0254e1fa713fbfc766387505e511robertphillips        fRect.sort();
16905302f8f24cf0254e1fa713fbfc766387505e511robertphillips
17005302f8f24cf0254e1fa713fbfc766387505e511robertphillips        if (fRect.isEmpty()) {
1715985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            this->setEmpty();
1725985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            return;
1735985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        }
1745985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
17505302f8f24cf0254e1fa713fbfc766387505e511robertphillips        SkScalar xRad = SkScalarHalf(fRect.width());
17605302f8f24cf0254e1fa713fbfc766387505e511robertphillips        SkScalar yRad = SkScalarHalf(fRect.height());
1775985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1785985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        for (int i = 0; i < 4; ++i) {
1795985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            fRadii[i].set(xRad, yRad);
1805985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        }
1815985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        fType = kOval_Type;
1825985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1835985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        SkDEBUGCODE(this->validate();)
1845985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
1855985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
186c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1875985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Initialize the RR with the same radii for all four corners.
1885985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1895985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad);
1905985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
191c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
192f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org     * Initialize the rr with one radius per-side.
193f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org     */
194f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org    void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad,
195f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org                      SkScalar rightRad, SkScalar bottomRad);
196f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org
197f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org    /**
1985985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Initialize the RR with potentially different radii for all four corners.
1995985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
2005985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setRectRadii(const SkRect& rect, const SkVector radii[4]);
2015985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
202c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    // The radii are stored in UL, UR, LR, LL order.
2035985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    enum Corner {
2045985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kUpperLeft_Corner,
2055985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kUpperRight_Corner,
2065985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kLowerRight_Corner,
2075985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kLowerLeft_Corner
2085985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    };
2095985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2105985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    const SkRect& rect() const { return fRect; }
2115985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    const SkVector& radii(Corner corner) const { return fRadii[corner]; }
2124ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    const SkRect& getBounds() const { return fRect; }
2134ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
2144ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    /**
2154ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  When a rrect is simple, all of its radii are equal. This returns one
2164ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  of those radii. This call requires the rrect to be non-complex.
2174ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     */
2184ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    const SkVector& getSimpleRadii() const {
2194ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com        SkASSERT(!this->isComplex());
2204ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com        return fRadii[0];
2214ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    }
2225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    friend bool operator==(const SkRRect& a, const SkRRect& b) {
2245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        return a.fRect == b.fRect &&
2254bd2bdbf04f21237337616aa931e34d7c8991edcdjsollen@google.com               SkScalarsEqual(a.fRadii[0].asScalars(),
2264bd2bdbf04f21237337616aa931e34d7c8991edcdjsollen@google.com                              b.fRadii[0].asScalars(), 8);
2275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
2285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    friend bool operator!=(const SkRRect& a, const SkRRect& b) {
2305985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        return a.fRect != b.fRect ||
2314bd2bdbf04f21237337616aa931e34d7c8991edcdjsollen@google.com               !SkScalarsEqual(a.fRadii[0].asScalars(),
2324bd2bdbf04f21237337616aa931e34d7c8991edcdjsollen@google.com                               b.fRadii[0].asScalars(), 8);
2335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
2345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    /**
236bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  Call inset on the bounds, and adjust the radii to reflect what happens
237bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  in stroking: If the corner is sharp (no curvature), leave it alone,
238bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  otherwise we grow/shrink the radii by the amount of the inset. If a
239bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  given radius becomes negative, it is pinned to 0.
240bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *
241bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  It is valid for dst == this.
242bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     */
24337071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const;
244bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org
24537071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void inset(SkScalar dx, SkScalar dy) {
24637071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org        this->inset(dx, dy, this);
24737071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    }
248bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org
249bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org    /**
250bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  Call outset on the bounds, and adjust the radii to reflect what happens
251bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  in stroking: If the corner is sharp (no curvature), leave it alone,
252bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  otherwise we grow/shrink the radii by the amount of the inset. If a
253bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  given radius becomes negative, it is pinned to 0.
254bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *
255bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  It is valid for dst == this.
256bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     */
25737071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const {
25837071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org        this->inset(-dx, -dy, dst);
25937071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    }
26037071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void outset(SkScalar dx, SkScalar dy) {
26137071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org        this->inset(-dx, -dy, this);
26237071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    }
263f1f66c0c8623805fdb88f09c0d87cbdd1745e12bskia.committer@gmail.com
264fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org    /**
265fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org     * Translate the rrect by (dx, dy).
266fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org     */
267fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org    void offset(SkScalar dx, SkScalar dy) {
268fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org        fRect.offset(dx, dy);
269fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org    }
27037071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org
27132c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com    /**
27232c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com     *  Returns true if 'rect' is wholy inside the RR, and both
27332c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com     *  are not empty.
27432c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com     */
27532c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com    bool contains(const SkRect& rect) const;
27632c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com
2775985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    SkDEBUGCODE(void validate() const;)
2785985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2794ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    enum {
2804ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com        kSizeInMemory = 12 * sizeof(SkScalar)
2814ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    };
282306ab9d5de38f2a547fd1d69aedbe69b5c6617ccskia.committer@gmail.com
2834ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    /**
2844ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  Write the rrect into the specified buffer. This is guaranteed to always
2854ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  write kSizeInMemory bytes, and that value is guaranteed to always be
2864ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  a multiple of 4. Return kSizeInMemory.
2874ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     */
2884faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    size_t writeToMemory(void* buffer) const;
2894ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
2904ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    /**
2914faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * Reads the rrect from the specified buffer
2924faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *
2934faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * If the specified buffer is large enough, this will read kSizeInMemory bytes,
2944faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * and that value is guaranteed to always be a multiple of 4.
2954faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *
2964faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @param buffer Memory to read from
2974faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @param length Amount of memory available in the buffer
2984faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @return number of bytes read (must be a multiple of 4) or
2994faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *         0 if there was not enough memory available
3004ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     */
3014faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    size_t readFromMemory(const void* buffer, size_t length);
3024ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
30320e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com    /**
30420e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  Transform by the specified matrix, and put the result in dst.
30520e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *
30620e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  @param matrix SkMatrix specifying the transform. Must only contain
30720e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *      scale and/or translate, or this call will fail.
30820e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  @param dst SkRRect to store the result. It is an error to use this,
30920e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *      which would make this function no longer const.
31020e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  @return true on success, false on failure. If false, dst is unmodified.
31120e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     */
31220e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com    bool transform(const SkMatrix& matrix, SkRRect* dst) const;
31320e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com
314e05fed0d6339c63c8cceff74af0b8d120c07e54creed    void dump(bool asHex) const;
315e05fed0d6339c63c8cceff74af0b8d120c07e54creed    void dump() const { this->dump(false); }
316e05fed0d6339c63c8cceff74af0b8d120c07e54creed    void dumpHex() const { this->dump(true); }
317b6b02526438d6839481fb40ccf610d28f7652397bsalomon
3185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comprivate:
3195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    SkRect fRect;
3205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[]
321c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    SkVector fRadii[4];
322727b8c1d1c0ba0634a97bff601e7af96bfd7daf8reed    // use an explicitly sized type so we're sure the class is dense (no uninitialized bytes)
3238aacf2085673f6302a43d590d4d2890789b87192mtklein    int32_t fType;
3245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    // TODO: add padding so we can use memcpy for flattening and not copy
3255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    // uninitialized data
3265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
3278aacf2085673f6302a43d590d4d2890789b87192mtklein    void computeType();
32832c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com    bool checkCornerContainment(SkScalar x, SkScalar y) const;
3295a70bc7f3cd32aaccc137c7d650cea613baa2443caryclark    void scaleRadii();
3304ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
3314ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    // to access fRadii directly
3324ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    friend class SkPath;
3335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com};
3345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
335852030103e47fabc3c766122140920fa19e17775robertphillips@google.com#endif
336