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_DottedCornerFinder_h_
7 : #define mozilla_DottedCornerFinder_h_
8 :
9 : #include "mozilla/gfx/2D.h"
10 : #include "mozilla/gfx/BezierUtils.h"
11 : #include "gfxRect.h"
12 :
13 : namespace mozilla {
14 :
15 : // Calculate C_i and r_i for each filled/unfilled circles in dotted corner.
16 : // Returns circle with C_{2j} and r_{2j} where 0 < 2j < n.
17 : //
18 : // ____-----------+
19 : // __---- ***** ###|
20 : // __---- ********* ####|
21 : // __--- ##### ***********#####|
22 : // _-- ######### *****+*****#####+ C_0
23 : // _- ########### *** C_1****#####|
24 : // / #####+##### ********* ####|
25 : // / . ### C_2 ### ***** ###|
26 : // | ######### ____-------+
27 : // | . #####____-----
28 : // | __----
29 : // | . /
30 : // | /
31 : // | ***** |
32 : // | ******* |
33 : // |*********|
34 : // |****+****|
35 : // | C_{n-1} |
36 : // | ******* |
37 : // | ***** |
38 : // | ##### |
39 : // | ####### |
40 : // |#########|
41 : // +----+----+
42 : // C_n
43 :
44 : class DottedCornerFinder
45 : {
46 : typedef mozilla::gfx::Bezier Bezier;
47 : typedef mozilla::gfx::Float Float;
48 : typedef mozilla::gfx::Point Point;
49 : typedef mozilla::gfx::Size Size;
50 :
51 : public:
52 : struct Result
53 : {
54 : // Center point of dot and its radius.
55 : Point C;
56 : Float r;
57 :
58 0 : Result(const Point& aC, Float aR)
59 0 : : C(aC), r(aR)
60 : {
61 0 : MOZ_ASSERT(aR >= 0);
62 0 : }
63 : };
64 :
65 : // aBorderRadiusX
66 : // aCornerDim.width
67 : // |<----------------->|
68 : // | | v
69 : // --+-------------___---+--
70 : // ^ | __-- | |
71 : // | | _- | | aR0
72 : // | | / aC0 +--
73 : // | | / | ^
74 : // | | | |
75 : // aBorderRadiusY | | | __--+
76 : // aCornerDim.height | || _-
77 : // | || /
78 : // | | /
79 : // | | |
80 : // | | |
81 : // | | |
82 : // | | |
83 : // v | aCn |
84 : // --+----+----+
85 : // | |
86 : // |<-->|
87 : // aRn
88 : //
89 : // aCornerDim and (aBorderRadiusX, aBorderRadiusY) can be different when
90 : // aBorderRadiusX is smaller than aRn*2 or
91 : // aBorderRadiusY is smaller than aR0*2.
92 : //
93 : // aCornerDim.width
94 : // |<----------------->|
95 : // | |
96 : // | aBorderRadiusX |
97 : // |<--------->| |
98 : // | | |
99 : // -------------------+-------__--+-------+--
100 : // ^ ^ | _- | ^
101 : // | | | / | |
102 : // | | | / | |
103 : // | aBorderRadiusY | | | | | aR0
104 : // | | || | |
105 : // | | | | |
106 : // aCornerDim.height | v | | v
107 : // | --+ aC0 +--
108 : // | | |
109 : // | | |
110 : // | | |
111 : // | | |
112 : // | | |
113 : // v | aCn |
114 : // -------------------+---------+---------+
115 : // | |
116 : // |<------->|
117 : // aRn
118 : DottedCornerFinder(const Bezier& aOuterBezier, const Bezier& aInnerBezier,
119 : mozilla::Corner aCorner,
120 : Float aBorderRadiusX, Float aBorderRadiusY,
121 : const Point& aC0, Float aR0, const Point& aCn, Float aRn,
122 : const Size& aCornerDim);
123 :
124 : bool HasMore(void) const;
125 : Result Next(void);
126 :
127 : private:
128 : static const size_t MAX_LOOP = 32;
129 :
130 : // Bezier control points for the outer curve, the inner curve, and a curve
131 : // that center points of circles are on (center curve).
132 : //
133 : // ___---+ outer curve
134 : // __-- |
135 : // _- |
136 : // / __---+ center curve
137 : // / __-- |
138 : // | / |
139 : // | / __--+ inner curve
140 : // | | _-
141 : // | | /
142 : // | | /
143 : // | | |
144 : // | | |
145 : // | | |
146 : // | | |
147 : // | | |
148 : // +----+----+
149 : Bezier mOuterBezier;
150 : Bezier mInnerBezier;
151 : Bezier mCenterBezier;
152 :
153 : mozilla::Corner mCorner;
154 :
155 : // Sign of the normal vector used in radius calculation, flipped depends on
156 : // corner and start and end radii.
157 : Float mNormalSign;
158 :
159 : // Center points and raii for start and end circles, mR0 >= mRn.
160 : // mMaxR = max(mR0, mRn)
161 : //
162 : // v
163 : // ___---+------
164 : // __-- #|# | mRn
165 : // _- ##|## |
166 : // / ##+## ---
167 : // / mCn ^
168 : // | #|#
169 : // | __--+
170 : // | _-
171 : // | /
172 : // | /
173 : // | |
174 : // | |
175 : // | ##### |
176 : // | ####### |
177 : // |#########|
178 : // +----+----+
179 : // |## mC0 ##|
180 : // | ####### |
181 : // | ##### |
182 : // | |
183 : // |<-->|
184 : //
185 : // mR0
186 : //
187 : Point mC0;
188 : Point mCn;
189 : Float mR0;
190 : Float mRn;
191 : Float mMaxR;
192 :
193 : // Parameters for the center curve with perfect circle and the inner curve.
194 : // The center curve doesn't necessarily share the origin with others.
195 : //
196 : // ___---+
197 : // __-- |
198 : // _- |
199 : // / __-+ |
200 : // / __-- |
201 : // | / |
202 : // | / __--+--
203 : // | | _- | ^
204 : // | | / | |
205 : // | | / | |
206 : // | | | | |
207 : // | | | | | mInnerHeight
208 : // | | | | |
209 : // | + | | |
210 : // | | | v
211 : // +---------+---------+
212 : // | | mInnerCurveOrigin
213 : // |<------->|
214 : // mInnerWidth
215 : //
216 : // ___---+
217 : // __--
218 : // _-
219 : // / __-+
220 : // / __-- |
221 : // | / |
222 : // | / __--+
223 : // | | _- |
224 : // | | / |
225 : // | | / |
226 : // | | | |
227 : // | | | |
228 : // | | | |
229 : // | +--- | ------+
230 : // | | | | mCenterCurveOrigin
231 : // + | + |
232 : // | |
233 : // | |
234 : // | |
235 : // | |
236 : // |<---------->|
237 : // mCenterCurveR
238 : //
239 : Point mCenterCurveOrigin;
240 : Float mCenterCurveR;
241 : Point mInnerCurveOrigin;
242 : Float mInnerWidth;
243 : Float mInnerHeight;
244 :
245 : Point mLastC;
246 : Float mLastR;
247 : Float mLastT;
248 :
249 : // Overlap between two circles.
250 : // It uses arc length on PERFECT, SINGLE_CURVE_AND_RADIUS, and SINGLE_CURVE,
251 : // and direct distance on OTHER.
252 : Float mBestOverlap;
253 :
254 : // If one of border-widths is 0, do not calculate overlap, and draw circles
255 : // until it reaches the other side or exceeds mMaxCount.
256 : bool mHasZeroBorderWidth;
257 : bool mHasMore;
258 :
259 : // The maximum number of filled/unfilled circles.
260 : size_t mMaxCount;
261 :
262 : enum {
263 : // radius.width
264 : // |<----------------->|
265 : // | |
266 : // --+-------------___---+----
267 : // ^ | __-- #|# ^
268 : // | | _- ##|## |
269 : // | | / ##+## | top-width
270 : // | | / ##|## |
271 : // | | | #|# v
272 : // | | | __--+----
273 : // radius.height | || _-
274 : // | || /
275 : // | | /
276 : // | | |
277 : // | | |
278 : // | | ##### |
279 : // | | ####### |
280 : // v |#########|
281 : // --+----+----+
282 : // |#########|
283 : // | ####### |
284 : // | ##### |
285 : // | |
286 : // |<------->|
287 : // left-width
288 :
289 : // * top-width == left-width
290 : // * radius.width == radius.height
291 : // * top-width < radius.width * 2
292 : //
293 : // All circles has same radii and are on single perfect circle's arc.
294 : // Overlap is known.
295 : //
296 : // Split the perfect circle's arc into 2n segments, each segment's length is
297 : // top-width * (1 - overlap). Place each circle's center point C_i on each
298 : // end of the segment, each circle's radius r_i is top-width / 2
299 : //
300 : // #####
301 : // #######
302 : // perfect #########
303 : // circle's ___---+####
304 : // arc ##### __-- ## C_0 ##
305 : // | #####_- ###|###
306 : // | ####+#### ##|##
307 : // | ##/C_i ## |
308 : // | |###### |
309 : // | | ##### |
310 : // +->| |
311 : // | |
312 : // ##|## |
313 : // ###|### |
314 : // ####|#### |
315 : // ####+-------------------+
316 : // ## C_n ##
317 : // #######
318 : // #####
319 : PERFECT,
320 :
321 : // * top-width == left-width
322 : // * 0.5 < radius.width / radius.height < 2.0
323 : // * top-width < min(radius.width, radius.height) * 2
324 : //
325 : // All circles has same radii and are on single elliptic arc.
326 : // Overlap is known.
327 : //
328 : // Split the elliptic arc into 2n segments, each segment's length is
329 : // top-width * (1 - overlap). Place each circle's center point C_i on each
330 : // end of the segment, each circle's radius r_i is top-width / 2
331 : //
332 : // #####
333 : // #######
334 : // ##### #########
335 : // ####### ____----+####
336 : // elliptic ######__--- ## C_0 ##
337 : // arc ##__+-### ###|###
338 : // | / # C_i # ##|##
339 : // +--> / ##### |
340 : // | |
341 : // ###|# |
342 : // ###|### |
343 : // ####|#### |
344 : // ####+------------------------+
345 : // ## C_n ##
346 : // #######
347 : // #####
348 : SINGLE_CURVE_AND_RADIUS,
349 :
350 : // * top-width != left-width
351 : // * 0 < min(top-width, left-width)
352 : // * 0.5 < radius.width / radius.height < 2.0
353 : // * max(top-width, left-width) < min(radius.width, radius.height) * 2
354 : //
355 : // All circles are on single elliptic arc.
356 : // Overlap is unknown.
357 : //
358 : // Place each circle's center point C_i on elliptic arc, each circle's
359 : // radius r_i is the distance between the center point and the inner curve.
360 : // The arc segment's length between C_i and C_{i-1} is
361 : // (r_i + r_{i-1}) * (1 - overlap).
362 : //
363 : // outer curve
364 : // /
365 : // /
366 : // / / center curve
367 : // / ####### /
368 : // /## /#
369 : // +# / #
370 : // /# / #
371 : // / # C_i / #
372 : // / # + # /
373 : // / # / \ # / inner curve
374 : // # / \ #/
375 : // # / r_i \+
376 : // #/ ##/
377 : // / ####### /
378 : // /
379 : SINGLE_CURVE,
380 :
381 : // Other cases.
382 : // Circles are not on single elliptic arc.
383 : // Overlap are unknown.
384 : //
385 : // Place tangent point innerTangent on the inner curve and find circle's
386 : // center point C_i and radius r_i where the circle is also tangent to the
387 : // outer curve.
388 : // Distance between C_i and C_{i-1} is (r_i + r_{i-1}) * (1 - overlap).
389 : //
390 : // outer curve
391 : // /
392 : // /
393 : // /
394 : // / #######
395 : // /## ##
396 : // +# #
397 : // /# \ #
398 : // / # \ #
399 : // / # + # /
400 : // / # C_i \ # / inner curve
401 : // # \ #/
402 : // # r_i \+
403 : // ## ##/ innerTangent
404 : // ####### /
405 : // /
406 : OTHER
407 : } mType;
408 :
409 : size_t mI;
410 : size_t mCount;
411 :
412 : // Determine mType from parameters.
413 : void DetermineType(Float aBorderRadiusX, Float aBorderRadiusY);
414 :
415 : // Reset calculation.
416 : void Reset(void);
417 :
418 : // Find radius for the given tangent point on the inner curve such that the
419 : // circle is also tangent to the outer curve.
420 : void FindPointAndRadius(Point& C, Float& r, const Point& innerTangent,
421 : const Point& normal, Float t);
422 :
423 : // Find next dot.
424 : Float FindNext(Float overlap);
425 :
426 : // Find mBestOverlap for parameters.
427 : void FindBestOverlap(Float aMinR,
428 : Float aMinBorderRadius, Float aMaxBorderRadius);
429 :
430 : // Fill corner with dots with given overlap, and return the number of dots
431 : // and last two dots's overlap.
432 : bool GetCountAndLastOverlap(Float aOverlap,
433 : size_t* aCount, Float* aActualOverlap);
434 : };
435 :
436 : } // namespace mozilla
437 :
438 : #endif /* mozilla_DottedCornerFinder_h_ */
|