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;
161e3b79e0c6480ea7e372ec4e5a2c5e11a03a845dBrian Salomonclass SkRBuffer;
171e3b79e0c6480ea7e372ec4e5a2c5e11a03a845dBrian Salomonclass SkWBuffer;
184ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com// Path forward:
205985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   core work
215985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add contains(SkRect&)  - for clip stack
225985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add contains(SkRRect&) - for clip stack
235985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add heart rect computation (max rect inside RR)
245985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add 9patch rect computation
255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add growToInclude(SkPath&)
265985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   analysis
275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      use growToInclude to fit skp round rects & generate stats (RRs vs. real paths)
285985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      check on # of rectorus's the RRs could handle
295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   rendering work
3014e50ae2a1b1cccdace599247b8c788b8db33ef4commit-bot@chromium.org//      update SkPath.addRRect() to only use quads
315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      add GM and bench
325985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//   further out
335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com//      detect and triangulate RRectorii rather than falling back to SW in Ganesh
34c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com//
355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com/** \class SkRRect
375985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
38c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    The SkRRect class represents a rounded rect with a potentially different
39c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    radii for each corner. It does not have a constructor so must be
40c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    initialized with one of the initialization functions (e.g., setEmpty,
415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    setRectRadii, etc.)
425985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
43c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    This class is intended to roughly match CSS' border-*-*-radius capabilities.
445985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    This means:
45c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        If either of a corner's radii are 0 the corner will be square.
465985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        Negative radii are not allowed (they are clamped to zero).
475985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        If the corner curves overlap they will be proportionally reduced to fit.
485985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com*/
495985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comclass SK_API SkRRect {
505985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.compublic:
510a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    /** Default initialized to a rrect at the origin with zero width and height. */
520a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    SkRRect() = default;
530a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon
547f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon    SkRRect(const SkRRect&) = default;
557f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon    SkRRect& operator=(const SkRRect&) = default;
567f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon
57c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
585985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Enum to capture the various possible subtypes of RR. Accessed
595985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * by type(). The subtypes become progressively less restrictive.
605985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
615985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    enum Type {
620a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon        // !< The RR has zero width and/or zero height. All radii are zero.
635985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kEmpty_Type,
645985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
655985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< The RR is actually a (non-empty) rect (i.e., at least one radius
665985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< at each corner is zero)
67c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        kRect_Type,
685985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
69c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        //!< The RR is actually a (non-empty) oval (i.e., all x radii are equal
705985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< and >= width/2 and all the y radii are equal and >= height/2
71c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        kOval_Type,
725985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
73c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        //!< The RR is non-empty and all the x radii are equal & all y radii
74c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        //!< are equal but it is not an oval (i.e., there are lines between
755985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< the curves) nor a rect (i.e., both radii are non-zero)
76c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com        kSimple_Type,
775985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
78f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< The RR is non-empty and the two left x radii are equal, the two top
79f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< y radii are equal, and the same for the right and bottom but it is
80f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< neither an rect, oval, nor a simple RR. It is called "nine patch"
81f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< because the centers of the corner ellipses form an axis aligned
82f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< rect with edges that divide the RR into an 9 rectangular patches:
83f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        //!< an interior patch, four edge patches, and four corner patches.
84f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org        kNinePatch_Type,
85f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org
865985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< A fully general (non-empty) RR. Some of the x and/or y radii are
875985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< different from the others and there must be one corner where
885985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        //!< both radii are non-zero.
895985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kComplex_Type,
90ba9741d46718c44d6e95e990c476d865c1cf4e55Adrienne Walker
91ba9741d46718c44d6e95e990c476d865c1cf4e55Adrienne Walker        kLastType = kComplex_Type,
925985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    };
935985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
94c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
955985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Returns the RR's sub type.
965985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
974ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    Type getType() const {
9849da334086c4a2c0bc4cb99e97965600dcb72f73Robert Phillips        SkASSERT(this->isValid());
99727b8c1d1c0ba0634a97bff601e7af96bfd7daf8reed        return static_cast<Type>(fType);
1005985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
1015985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1024ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    Type type() const { return this->getType(); }
1034ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
1044ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isEmpty() const { return kEmpty_Type == this->getType(); }
1054ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isRect() const { return kRect_Type == this->getType(); }
1064ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isOval() const { return kOval_Type == this->getType(); }
1074ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isSimple() const { return kSimple_Type == this->getType(); }
108f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org    inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); }
1094ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    inline bool isComplex() const { return kComplex_Type == this->getType(); }
1104ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
11137071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    SkScalar width() const { return fRect.width(); }
11237071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    SkScalar height() const { return fRect.height(); }
11337071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org
114c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
115242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed     *  kSimple means that all corners have the same x,y radii. This returns the top/left
116242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed     *  corner's radii as representative of all corners. If the RRect is kComplex, then
117242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed     *  this still returns that corner's radii, but it is not indicative of the other corners.
118242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed     */
119242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed    SkVector getSimpleRadii() const {
120242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed        return fRadii[0];
121242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed    }
122242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed
123242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed    /**
1240a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     * Same as default initialized - zero width and height at the origin.
1255985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1260a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    void setEmpty() { *this = SkRRect(); }
1275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
128c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1295985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Set this RR to match the supplied rect. All radii will be 0.
1305985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1315985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setRect(const SkRect& rect) {
1320a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon        if (!this->initializeRect(rect)) {
1335985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            return;
1345985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        }
1355985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1365985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        memset(fRadii, 0, sizeof(fRadii));
1375985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        fType = kRect_Type;
1385985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
13949da334086c4a2c0bc4cb99e97965600dcb72f73Robert Phillips        SkASSERT(this->isValid());
1405985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
1415985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1420a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    /** Makes an empty rrect at the origin with zero width and height. */
1430a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    static SkRRect MakeEmpty() { return SkRRect(); }
144ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon
145021f631dc66da06dbe4aed21df2f27daecce9db7reed    static SkRRect MakeRect(const SkRect& r) {
146021f631dc66da06dbe4aed21df2f27daecce9db7reed        SkRRect rr;
147021f631dc66da06dbe4aed21df2f27daecce9db7reed        rr.setRect(r);
148021f631dc66da06dbe4aed21df2f27daecce9db7reed        return rr;
149021f631dc66da06dbe4aed21df2f27daecce9db7reed    }
150ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon
15130c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    static SkRRect MakeOval(const SkRect& oval) {
15230c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        SkRRect rr;
15330c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        rr.setOval(oval);
15430c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips        return rr;
15530c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips    }
15630c4cae7d3a26252e7e45adf6e5722b34adf6848robertphillips
1574a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon    static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) {
1584a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon        SkRRect rr;
1594a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon        rr.setRectXY(rect, xRad, yRad);
1604a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon        return rr;
1614a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon    }
1624a4f14ba3f93cc6bb9146be0f029a9badb1b95d9bsalomon
163c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1645985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Set this RR to match the supplied oval. All x radii will equal half the
1655985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * width and all y radii will equal half the height.
1665985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1675985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setOval(const SkRect& oval) {
1680a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon        if (!this->initializeRect(oval)) {
1695985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            return;
1705985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        }
1715985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
17205302f8f24cf0254e1fa713fbfc766387505e511robertphillips        SkScalar xRad = SkScalarHalf(fRect.width());
17305302f8f24cf0254e1fa713fbfc766387505e511robertphillips        SkScalar yRad = SkScalarHalf(fRect.height());
1745985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
1755985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        for (int i = 0; i < 4; ++i) {
1765985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com            fRadii[i].set(xRad, yRad);
1775985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        }
1785985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        fType = kOval_Type;
1795985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
18049da334086c4a2c0bc4cb99e97965600dcb72f73Robert Phillips        SkASSERT(this->isValid());
1815985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
1825985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
183c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
1845985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Initialize the RR with the same radii for all four corners.
1855985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1865985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad);
1875985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
188c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    /**
189f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org     * Initialize the rr with one radius per-side.
190f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org     */
191f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org    void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad,
192f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org                      SkScalar rightRad, SkScalar bottomRad);
193f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org
194f338d7c860bf0bca82cac793069522311a3dbb1acommit-bot@chromium.org    /**
1955985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     * Initialize the RR with potentially different radii for all four corners.
1965985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com     */
1975985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    void setRectRadii(const SkRect& rect, const SkVector radii[4]);
1985985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
199c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com    // The radii are stored in UL, UR, LR, LL order.
2005985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    enum Corner {
2015985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kUpperLeft_Corner,
2025985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kUpperRight_Corner,
2035985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kLowerRight_Corner,
2045985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com        kLowerLeft_Corner
2055985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    };
2065985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2075985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    const SkRect& rect() const { return fRect; }
208242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed    SkVector radii(Corner corner) const { return fRadii[corner]; }
2094ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    const SkRect& getBounds() const { return fRect; }
2104ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
2115985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    friend bool operator==(const SkRRect& a, const SkRRect& b) {
212df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark        return a.fRect == b.fRect && SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8);
2135985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
2145985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2155985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    friend bool operator!=(const SkRRect& a, const SkRRect& b) {
216df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark        return a.fRect != b.fRect || !SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8);
2175985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    }
2185985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2195985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com    /**
220bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  Call inset on the bounds, and adjust the radii to reflect what happens
221bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  in stroking: If the corner is sharp (no curvature), leave it alone,
222bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  otherwise we grow/shrink the radii by the amount of the inset. If a
223bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  given radius becomes negative, it is pinned to 0.
224bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *
2250a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     *  If the inset amount is larger than the width/height then the rrect collapses to
2260a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     *  a degenerate line or point.
2270a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     *
2280a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     *  If the inset is sufficiently negative to cause the bounds to become infinite then
2290a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     *  the result is a default initialized rrect.
2300a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     *
231bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  It is valid for dst == this.
232bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     */
23337071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const;
234bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org
23537071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void inset(SkScalar dx, SkScalar dy) {
23637071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org        this->inset(dx, dy, this);
23737071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    }
238bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org
239bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org    /**
240bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  Call outset on the bounds, and adjust the radii to reflect what happens
241bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  in stroking: If the corner is sharp (no curvature), leave it alone,
242bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  otherwise we grow/shrink the radii by the amount of the inset. If a
243bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  given radius becomes negative, it is pinned to 0.
244bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *
245bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     *  It is valid for dst == this.
246bcbef579d02e255b9a29b5db2d6804f4bfc76d1cmike@reedtribe.org     */
24737071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const {
24837071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org        this->inset(-dx, -dy, dst);
24937071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    }
25037071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    void outset(SkScalar dx, SkScalar dy) {
25137071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org        this->inset(-dx, -dy, this);
25237071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org    }
253f1f66c0c8623805fdb88f09c0d87cbdd1745e12bskia.committer@gmail.com
254fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org    /**
255fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org     * Translate the rrect by (dx, dy).
256fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org     */
257fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org    void offset(SkScalar dx, SkScalar dy) {
258fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org        fRect.offset(dx, dy);
259fbde87f53d659ae2bd616751e466c887b0f3bee5commit-bot@chromium.org    }
26037071640f6bdcb1bfb193f85b9ca615b29679425mike@reedtribe.org
2617f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon    SkRRect SK_WARN_UNUSED_RESULT makeOffset(SkScalar dx, SkScalar dy) const {
2627f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon        return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType);
2637f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon    }
2647f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon
26532c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com    /**
26632c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com     *  Returns true if 'rect' is wholy inside the RR, and both
26732c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com     *  are not empty.
26832c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com     */
26932c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com    bool contains(const SkRect& rect) const;
27032c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com
27149da334086c4a2c0bc4cb99e97965600dcb72f73Robert Phillips    bool isValid() const;
2725985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
2734ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    enum {
2744ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com        kSizeInMemory = 12 * sizeof(SkScalar)
2754ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    };
276306ab9d5de38f2a547fd1d69aedbe69b5c6617ccskia.committer@gmail.com
2774ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    /**
2784ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  Write the rrect into the specified buffer. This is guaranteed to always
2794ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  write kSizeInMemory bytes, and that value is guaranteed to always be
2804ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     *  a multiple of 4. Return kSizeInMemory.
2814ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     */
2824faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    size_t writeToMemory(void* buffer) const;
2831e3b79e0c6480ea7e372ec4e5a2c5e11a03a845dBrian Salomon    void writeToBuffer(SkWBuffer*) const;
2844ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
2854ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    /**
2864faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * Reads the rrect from the specified buffer
2874faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *
2884faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * If the specified buffer is large enough, this will read kSizeInMemory bytes,
2894faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * and that value is guaranteed to always be a multiple of 4.
2904faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *
2914faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @param buffer Memory to read from
2924faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @param length Amount of memory available in the buffer
2934faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @return number of bytes read (must be a multiple of 4) or
2944faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *         0 if there was not enough memory available
2954ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com     */
2964faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    size_t readFromMemory(const void* buffer, size_t length);
2971e3b79e0c6480ea7e372ec4e5a2c5e11a03a845dBrian Salomon    bool readFromBuffer(SkRBuffer*);
2984ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
29920e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com    /**
30020e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  Transform by the specified matrix, and put the result in dst.
30120e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *
30220e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  @param matrix SkMatrix specifying the transform. Must only contain
30320e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *      scale and/or translate, or this call will fail.
30420e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *  @param dst SkRRect to store the result. It is an error to use this,
30520e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     *      which would make this function no longer const.
30620d479c088ad6dc06e16b13a3e6b2dfefa845430Mike Klein     *  @return true on success, false on failure.
30720e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com     */
30820e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com    bool transform(const SkMatrix& matrix, SkRRect* dst) const;
30920e3cd2c9fbc049eae8bcedc591c2cc8d4bed656scroggo@google.com
310e05fed0d6339c63c8cceff74af0b8d120c07e54creed    void dump(bool asHex) const;
311e05fed0d6339c63c8cceff74af0b8d120c07e54creed    void dump() const { this->dump(false); }
312e05fed0d6339c63c8cceff74af0b8d120c07e54creed    void dumpHex() const { this->dump(true); }
313b6b02526438d6839481fb40ccf610d28f7652397bsalomon
3145985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.comprivate:
315242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed    static bool AreRectAndRadiiValid(const SkRect&, const SkVector[4]);
316242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed
3177f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon    SkRRect(const SkRect& rect, const SkVector radii[4], int32_t type)
3187f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon        : fRect(rect)
3197f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon        , fRadii{radii[0], radii[1], radii[2], radii[3]}
3207f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon        , fType(type) {}
3217f0d9f39206d0bf67e0a14e9cf3351243c9b5a1bbsalomon
3220a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    /**
3230a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     * Initializes fRect. If the passed in rect is not finite or empty the rrect will be fully
3240a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     * initialized and false is returned. Otherwise, just fRect is initialized and true is returned.
3250a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon     */
3260a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    bool initializeRect(const SkRect&);
3275985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
3288aacf2085673f6302a43d590d4d2890789b87192mtklein    void computeType();
32932c1b66a2c4f26935ba59f3afe3e81600fade78drobertphillips@google.com    bool checkCornerContainment(SkScalar x, SkScalar y) const;
3305a70bc7f3cd32aaccc137c7d650cea613baa2443caryclark    void scaleRadii();
3314ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
3320a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    SkRect fRect = SkRect::MakeEmpty();
3330a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[]
3340a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    SkVector fRadii[4] = {{0, 0}, {0, 0}, {0,0}, {0,0}};
3350a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    // use an explicitly sized type so we're sure the class is dense (no uninitialized bytes)
3360a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    int32_t fType = kEmpty_Type;
3370a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon    // TODO: add padding so we can use memcpy for flattening and not copy uninitialized data
3380a241ce808511ceb1c72d6f2473b01b455ac5101Brian Salomon
3394ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    // to access fRadii directly
3404ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com    friend class SkPath;
341242135a402592e4fb40c5aba44cf8d483e68d292Mike Reed    friend class SkRRectPriv;
3425985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com};
3435985e7c4d13b04d6b819bfff3df44f1dd3eb35b8robertphillips@google.com
344852030103e47fabc3c766122140920fa19e17775robertphillips@google.com#endif
345