Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef mozilla_DashedCornerFinder_h_
7 : #define mozilla_DashedCornerFinder_h_
8 :
9 : #include "mozilla/gfx/2D.h"
10 : #include "mozilla/gfx/BezierUtils.h"
11 :
12 : namespace mozilla {
13 :
14 : // Calculate {OuterT_i, InnerT_i} for each 1 < i < n, that
15 : // (OuterL_i + InnerL_i) / 2 == dashLength * (W_i + W_{i-1}) / 2
16 : // where
17 : // OuterP_i: OuterCurve(OuterT_i)
18 : // InnerP_i: InnerCurve(OuterT_i)
19 : // OuterL_i: Elliptic arc length between OuterP_i - OuterP_{i-1}
20 : // InnerL_i: Elliptic arc length between InnerP_i - InnerP_{i-1}
21 : // W_i = |OuterP_i - InnerP_i|
22 : // 1.0 < dashLength < 3.0
23 : //
24 : // OuterP_1 OuterP_0
25 : // _+__-----------+ OuterCurve
26 : // OuterP_2 __---- | OuterL_1 |
27 : // __+--- | |
28 : // __--- | OuterL_2 | |
29 : // OuterP_3 _-- | | W_1 | W_0
30 : // _+ | | |
31 : // / \ W_2 | | |
32 : // / \ | | InnerL_1 |
33 : // | \ | InnerL_2|____-------+ InnerCurve
34 : // | \ |____----+ InnerP_0
35 : // | . \ __---+ InnerP_1
36 : // | \ / InnerP_2
37 : // | . /+ InnerP_3
38 : // | |
39 : // | . |
40 : // | |
41 : // | |
42 : // | |
43 : // OuterP_{n-1} +--------+ InnerP_{n-1}
44 : // | |
45 : // | |
46 : // | |
47 : // | |
48 : // | |
49 : // OuterP_n +--------+ InnerP_n
50 : //
51 : // Returns region with [OuterCurve((OuterT_{2j} + OuterT_{2j-1}) / 2),
52 : // OuterCurve((OuterT_{2j} + OuterT_{2j-1}) / 2),
53 : // InnerCurve((OuterT_{2j} + OuterT_{2j+1}) / 2),
54 : // InnerCurve((OuterT_{2j} + OuterT_{2j+1}) / 2)],
55 : // to start and end with half segment.
56 : //
57 : // _+__----+------+ OuterCurve
58 : // _+---- | |######|
59 : // __+---#| | |######|
60 : // _+---##|####| | |######|
61 : // _-- |#####|#####| | |#####|
62 : // _+ |#####|#####| | |#####|
63 : // / \ |#####|####| | |#####|
64 : // / \ |####|#####| | |#####|
65 : // | \ |####|####| |____-+-----+ InnerCurve
66 : // | \ |####|____+---+
67 : // | . \ __+---+
68 : // | \ /
69 : // | . /+
70 : // | |
71 : // | . |
72 : // | |
73 : // | |
74 : // | |
75 : // +--------+
76 : // | |
77 : // | |
78 : // +--------+
79 : // |########|
80 : // |########|
81 : // +--------+
82 :
83 : class DashedCornerFinder
84 : {
85 : typedef mozilla::gfx::Bezier Bezier;
86 : typedef mozilla::gfx::Float Float;
87 : typedef mozilla::gfx::Point Point;
88 : typedef mozilla::gfx::Size Size;
89 :
90 : public:
91 : struct Result
92 : {
93 : // Control points for the outer curve and the inner curve.
94 : //
95 : // outerSectionBezier
96 : // |
97 : // v _+ 3
98 : // ___---#|
99 : // 0 +---#######|
100 : // |###########|
101 : // |###########|
102 : // |##########|
103 : // |##########|
104 : // |#########|
105 : // |#####____+ 3
106 : // 0 +----
107 : // ^
108 : // |
109 : // innerSectionBezier
110 : Bezier outerSectionBezier;
111 : Bezier innerSectionBezier;
112 :
113 0 : Result(const Bezier& aOuterSectionBezier,
114 : const Bezier& aInnerSectionBezier)
115 0 : : outerSectionBezier(aOuterSectionBezier),
116 0 : innerSectionBezier(aInnerSectionBezier)
117 0 : {}
118 : };
119 :
120 : // aCornerDim.width
121 : // |<----------------->|
122 : // | |
123 : // --+-------------___---+--
124 : // ^ | __-- | ^
125 : // | | _- | |
126 : // | | / | | aBorderWidthH
127 : // | | / | |
128 : // | | | | v
129 : // | | | __--+--
130 : // aCornerDim.height | || _-
131 : // | || /
132 : // | | /
133 : // | | |
134 : // | | |
135 : // | | |
136 : // | | |
137 : // v | |
138 : // --+---------+
139 : // | |
140 : // |<------->|
141 : // aBorderWidthV
142 : DashedCornerFinder(const Bezier& aOuterBezier, const Bezier& aInnerBezier,
143 : Float aBorderWidthH, Float aBorderWidthV,
144 : const Size& aCornerDim);
145 :
146 : bool HasMore(void) const;
147 : Result Next(void);
148 :
149 : private:
150 : static const size_t MAX_LOOP = 32;
151 :
152 : // Bezier control points for the outer curve and the inner curve.
153 : //
154 : // ___---+ outer curve
155 : // __-- |
156 : // _- |
157 : // / |
158 : // / |
159 : // | |
160 : // | __--+ inner curve
161 : // | _-
162 : // | /
163 : // | /
164 : // | |
165 : // | |
166 : // | |
167 : // | |
168 : // | |
169 : // +---------+
170 : Bezier mOuterBezier;
171 : Bezier mInnerBezier;
172 :
173 : Point mLastOuterP;
174 : Point mLastInnerP;
175 : Float mLastOuterT;
176 : Float mLastInnerT;
177 :
178 : // Length for each segment, ratio of the border width at that point.
179 : Float mBestDashLength;
180 :
181 : // If one of border-widths is 0, do not calculate mBestDashLength, and draw
182 : // segments until it reaches the other side or exceeds mMaxCount.
183 : bool mHasZeroBorderWidth;
184 : bool mHasMore;
185 :
186 : // The maximum number of segments.
187 : size_t mMaxCount;
188 :
189 : enum {
190 : // radius.width
191 : // |<----------------->|
192 : // | |
193 : // --+-------------___---+--
194 : // ^ | __-- | ^
195 : // | | _- | |
196 : // | | / + | top-width
197 : // | | / | |
198 : // | | | | v
199 : // | | | __--+--
200 : // radius.height | || _-
201 : // | || /
202 : // | | /
203 : // | | |
204 : // | | |
205 : // | | |
206 : // | | |
207 : // v | |
208 : // --+----+----+
209 : // | |
210 : // |<------->|
211 : // left-width
212 :
213 : // * top-width == left-width
214 : // * radius.width == radius.height
215 : // * top-width < radius.width * 2
216 : //
217 : // Split the perfect circle's arc into 2n segments, each segment's length is
218 : // top-width * dashLength. Then split the inner curve and the outer curve
219 : // with same angles.
220 : //
221 : // radius.width
222 : // |<---------------------->|
223 : // | | v
224 : // --+------------------------+--
225 : // ^ | | | top-width / 2
226 : // | | perfect | |
227 : // | | circle's ___---+--
228 : // | | arc __-+ | ^
229 : // | | | _- | |
230 : // radius.height | | | + | +--
231 : // | | | / \ | |
232 : // | | | | \ | |
233 : // | | | | \ | |
234 : // | | +->| \ | |
235 : // | | +---__ \ | |
236 : // | | | --__ \ | |
237 : // | | | ---__ \ | |
238 : // v | | --_\||
239 : // --+----+----+--------------+
240 : // | | |
241 : // |<-->| |
242 : // left-width / 2
243 : PERFECT,
244 :
245 : // Other cases.
246 : //
247 : // Split the outer curve and the inner curve into 2n segments, each segment
248 : // satisfies following:
249 : // (OuterL_i + InnerL_i) / 2 == dashLength * (W_i + W_{i-1}) / 2
250 : OTHER
251 : } mType;
252 :
253 : size_t mI;
254 : size_t mCount;
255 :
256 : // Determine mType from parameters.
257 : void DetermineType(Float aBorderWidthH, Float aBorderWidthV);
258 :
259 : // Reset calculation.
260 : void Reset(void);
261 :
262 : // Find next segment.
263 : Float FindNext(Float dashLength);
264 :
265 : // Find mBestDashLength for parameters.
266 : void FindBestDashLength(Float aMinBorderWidth, Float aMaxBorderWidth,
267 : Float aMinBorderRadius, Float aMaxBorderRadius);
268 :
269 : // Fill corner with dashes with given dash length, and return the number of
270 : // segments and last segment's dash length.
271 : bool GetCountAndLastDashLength(Float aDashLength,
272 : size_t* aCount, Float* aActualDashLength);
273 : };
274 :
275 : } // namespace mozilla
276 :
277 : #endif /* mozilla_DashedCornerFinder_h_ */
|