Coverage Report

Created: 2018-09-25 14:53

/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_ */