Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "PathHelpers.h" |
michael@0 | 7 | |
michael@0 | 8 | namespace mozilla { |
michael@0 | 9 | namespace gfx { |
michael@0 | 10 | |
michael@0 | 11 | void |
michael@0 | 12 | AppendRoundedRectToPath(PathBuilder* aPathBuilder, |
michael@0 | 13 | const Rect& aRect, |
michael@0 | 14 | // paren's needed due to operator precedence: |
michael@0 | 15 | const Size(& aCornerRadii)[4], |
michael@0 | 16 | bool aDrawClockwise) |
michael@0 | 17 | { |
michael@0 | 18 | // For CW drawing, this looks like: |
michael@0 | 19 | // |
michael@0 | 20 | // ...******0** 1 C |
michael@0 | 21 | // **** |
michael@0 | 22 | // *** 2 |
michael@0 | 23 | // ** |
michael@0 | 24 | // * |
michael@0 | 25 | // * |
michael@0 | 26 | // 3 |
michael@0 | 27 | // * |
michael@0 | 28 | // * |
michael@0 | 29 | // |
michael@0 | 30 | // Where 0, 1, 2, 3 are the control points of the Bezier curve for |
michael@0 | 31 | // the corner, and C is the actual corner point. |
michael@0 | 32 | // |
michael@0 | 33 | // At the start of the loop, the current point is assumed to be |
michael@0 | 34 | // the point adjacent to the top left corner on the top |
michael@0 | 35 | // horizontal. Note that corner indices start at the top left and |
michael@0 | 36 | // continue clockwise, whereas in our loop i = 0 refers to the top |
michael@0 | 37 | // right corner. |
michael@0 | 38 | // |
michael@0 | 39 | // When going CCW, the control points are swapped, and the first |
michael@0 | 40 | // corner that's drawn is the top left (along with the top segment). |
michael@0 | 41 | // |
michael@0 | 42 | // There is considerable latitude in how one chooses the four |
michael@0 | 43 | // control points for a Bezier curve approximation to an ellipse. |
michael@0 | 44 | // For the overall path to be continuous and show no corner at the |
michael@0 | 45 | // endpoints of the arc, points 0 and 3 must be at the ends of the |
michael@0 | 46 | // straight segments of the rectangle; points 0, 1, and C must be |
michael@0 | 47 | // collinear; and points 3, 2, and C must also be collinear. This |
michael@0 | 48 | // leaves only two free parameters: the ratio of the line segments |
michael@0 | 49 | // 01 and 0C, and the ratio of the line segments 32 and 3C. See |
michael@0 | 50 | // the following papers for extensive discussion of how to choose |
michael@0 | 51 | // these ratios: |
michael@0 | 52 | // |
michael@0 | 53 | // Dokken, Tor, et al. "Good approximation of circles by |
michael@0 | 54 | // curvature-continuous Bezier curves." Computer-Aided |
michael@0 | 55 | // Geometric Design 7(1990) 33--41. |
michael@0 | 56 | // Goldapp, Michael. "Approximation of circular arcs by cubic |
michael@0 | 57 | // polynomials." Computer-Aided Geometric Design 8(1991) 227--238. |
michael@0 | 58 | // Maisonobe, Luc. "Drawing an elliptical arc using polylines, |
michael@0 | 59 | // quadratic, or cubic Bezier curves." |
michael@0 | 60 | // http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf |
michael@0 | 61 | // |
michael@0 | 62 | // We follow the approach in section 2 of Goldapp (least-error, |
michael@0 | 63 | // Hermite-type approximation) and make both ratios equal to |
michael@0 | 64 | // |
michael@0 | 65 | // 2 2 + n - sqrt(2n + 28) |
michael@0 | 66 | // alpha = - * --------------------- |
michael@0 | 67 | // 3 n - 4 |
michael@0 | 68 | // |
michael@0 | 69 | // where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ). |
michael@0 | 70 | // |
michael@0 | 71 | // This is the result of Goldapp's equation (10b) when the angle |
michael@0 | 72 | // swept out by the arc is pi/2, and the parameter "a-bar" is the |
michael@0 | 73 | // expression given immediately below equation (21). |
michael@0 | 74 | // |
michael@0 | 75 | // Using this value, the maximum radial error for a circle, as a |
michael@0 | 76 | // fraction of the radius, is on the order of 0.2 x 10^-3. |
michael@0 | 77 | // Neither Dokken nor Goldapp discusses error for a general |
michael@0 | 78 | // ellipse; Maisonobe does, but his choice of control points |
michael@0 | 79 | // follows different constraints, and Goldapp's expression for |
michael@0 | 80 | // 'alpha' gives much smaller radial error, even for very flat |
michael@0 | 81 | // ellipses, than Maisonobe's equivalent. |
michael@0 | 82 | // |
michael@0 | 83 | // For the various corners and for each axis, the sign of this |
michael@0 | 84 | // constant changes, or it might be 0 -- it's multiplied by the |
michael@0 | 85 | // appropriate multiplier from the list before using. |
michael@0 | 86 | |
michael@0 | 87 | const Float alpha = Float(0.55191497064665766025); |
michael@0 | 88 | |
michael@0 | 89 | typedef struct { Float a, b; } twoFloats; |
michael@0 | 90 | |
michael@0 | 91 | twoFloats cwCornerMults[4] = { { -1, 0 }, // cc == clockwise |
michael@0 | 92 | { 0, -1 }, |
michael@0 | 93 | { +1, 0 }, |
michael@0 | 94 | { 0, +1 } }; |
michael@0 | 95 | twoFloats ccwCornerMults[4] = { { +1, 0 }, // ccw == counter-clockwise |
michael@0 | 96 | { 0, -1 }, |
michael@0 | 97 | { -1, 0 }, |
michael@0 | 98 | { 0, +1 } }; |
michael@0 | 99 | |
michael@0 | 100 | twoFloats *cornerMults = aDrawClockwise ? cwCornerMults : ccwCornerMults; |
michael@0 | 101 | |
michael@0 | 102 | Point cornerCoords[] = { aRect.TopLeft(), aRect.TopRight(), |
michael@0 | 103 | aRect.BottomRight(), aRect.BottomLeft() }; |
michael@0 | 104 | |
michael@0 | 105 | Point pc, p0, p1, p2, p3; |
michael@0 | 106 | |
michael@0 | 107 | // The indexes of the corners: |
michael@0 | 108 | const int kTopLeft = 0, kTopRight = 1; |
michael@0 | 109 | |
michael@0 | 110 | if (aDrawClockwise) { |
michael@0 | 111 | aPathBuilder->MoveTo(Point(aRect.X() + aCornerRadii[kTopLeft].width, |
michael@0 | 112 | aRect.Y())); |
michael@0 | 113 | } else { |
michael@0 | 114 | aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aCornerRadii[kTopRight].width, |
michael@0 | 115 | aRect.Y())); |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | for (int i = 0; i < 4; ++i) { |
michael@0 | 119 | // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw) |
michael@0 | 120 | int c = aDrawClockwise ? ((i+1) % 4) : ((4-i) % 4); |
michael@0 | 121 | |
michael@0 | 122 | // i+2 and i+3 respectively. These are used to index into the corner |
michael@0 | 123 | // multiplier table, and were deduced by calculating out the long form |
michael@0 | 124 | // of each corner and finding a pattern in the signs and values. |
michael@0 | 125 | int i2 = (i+2) % 4; |
michael@0 | 126 | int i3 = (i+3) % 4; |
michael@0 | 127 | |
michael@0 | 128 | pc = cornerCoords[c]; |
michael@0 | 129 | |
michael@0 | 130 | if (aCornerRadii[c].width > 0.0 && aCornerRadii[c].height > 0.0) { |
michael@0 | 131 | p0.x = pc.x + cornerMults[i].a * aCornerRadii[c].width; |
michael@0 | 132 | p0.y = pc.y + cornerMults[i].b * aCornerRadii[c].height; |
michael@0 | 133 | |
michael@0 | 134 | p3.x = pc.x + cornerMults[i3].a * aCornerRadii[c].width; |
michael@0 | 135 | p3.y = pc.y + cornerMults[i3].b * aCornerRadii[c].height; |
michael@0 | 136 | |
michael@0 | 137 | p1.x = p0.x + alpha * cornerMults[i2].a * aCornerRadii[c].width; |
michael@0 | 138 | p1.y = p0.y + alpha * cornerMults[i2].b * aCornerRadii[c].height; |
michael@0 | 139 | |
michael@0 | 140 | p2.x = p3.x - alpha * cornerMults[i3].a * aCornerRadii[c].width; |
michael@0 | 141 | p2.y = p3.y - alpha * cornerMults[i3].b * aCornerRadii[c].height; |
michael@0 | 142 | |
michael@0 | 143 | aPathBuilder->LineTo(p0); |
michael@0 | 144 | aPathBuilder->BezierTo(p1, p2, p3); |
michael@0 | 145 | } else { |
michael@0 | 146 | aPathBuilder->LineTo(pc); |
michael@0 | 147 | } |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | aPathBuilder->Close(); |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | void |
michael@0 | 154 | AppendEllipseToPath(PathBuilder* aPathBuilder, |
michael@0 | 155 | const Point& aCenter, |
michael@0 | 156 | const Size& aDimensions) |
michael@0 | 157 | { |
michael@0 | 158 | Size halfDim = aDimensions / 2.0; |
michael@0 | 159 | Rect rect(aCenter - Point(halfDim.width, halfDim.height), aDimensions); |
michael@0 | 160 | Size radii[] = { halfDim, halfDim, halfDim, halfDim }; |
michael@0 | 161 | |
michael@0 | 162 | AppendRoundedRectToPath(aPathBuilder, rect, radii); |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | } // namespace gfx |
michael@0 | 166 | } // namespace mozilla |
michael@0 | 167 |