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