xref: /aosp_15_r20/external/pdfium/core/fxge/cfx_path_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2021 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "core/fxge/cfx_path.h"
6 
7 #include "core/fxcrt/fx_coordinates.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 
TEST(CFX_Path,BasicTest)10 TEST(CFX_Path, BasicTest) {
11   CFX_Path path;
12   path.AppendRect(/*left=*/1, /*bottom=*/2, /*right=*/3, /*top=*/5);
13   EXPECT_EQ(5u, path.GetPoints().size());
14   EXPECT_TRUE(path.IsRect());
15   absl::optional<CFX_FloatRect> rect = path.GetRect(nullptr);
16   ASSERT_TRUE(rect.has_value());
17   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), rect.value());
18   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), path.GetBoundingBox());
19 
20   const CFX_Matrix kScaleMatrix(1, 0, 0, 2, 60, 70);
21   rect = path.GetRect(&kScaleMatrix);
22   ASSERT_TRUE(rect.has_value());
23   EXPECT_EQ(CFX_FloatRect(61, 74, 63, 80), rect.value());
24   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), path.GetBoundingBox());
25 
26   path.Clear();
27   EXPECT_EQ(0u, path.GetPoints().size());
28   EXPECT_FALSE(path.IsRect());
29   EXPECT_EQ(CFX_FloatRect(), path.GetBoundingBox());
30 
31   // 4 points without a closed path makes a rect.
32   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
33   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
34   path.AppendPoint({1, 1}, CFX_Path::Point::Type::kLine);
35   path.AppendPoint({1, 0}, CFX_Path::Point::Type::kLine);
36   EXPECT_EQ(4u, path.GetPoints().size());
37   EXPECT_TRUE(path.IsRect());
38   rect = path.GetRect(nullptr);
39   ASSERT_TRUE(rect.has_value());
40   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
41   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), path.GetBoundingBox());
42 
43   // 4 points with a closed path also makes a rect.
44   path.ClosePath();
45   EXPECT_EQ(4u, path.GetPoints().size());
46   EXPECT_TRUE(path.IsRect());
47   rect = path.GetRect(nullptr);
48   ASSERT_TRUE(rect.has_value());
49   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
50   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), path.GetBoundingBox());
51 
52   path.Transform(kScaleMatrix);
53   EXPECT_TRUE(path.IsRect());
54   rect = path.GetRect(nullptr);
55   ASSERT_TRUE(rect.has_value());
56   EXPECT_EQ(CFX_FloatRect(60, 70, 61, 72), rect.value());
57   EXPECT_EQ(CFX_FloatRect(60, 70, 61, 72), path.GetBoundingBox());
58 
59   path.Clear();
60   path.AppendFloatRect({1, 2, 3, 5});
61   EXPECT_TRUE(path.IsRect());
62   rect = path.GetRect(nullptr);
63   ASSERT_TRUE(rect.has_value());
64   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), rect.value());
65   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), path.GetBoundingBox());
66 }
67 
TEST(CFX_Path,ShearTransform)68 TEST(CFX_Path, ShearTransform) {
69   CFX_Path path;
70   path.AppendRect(/*left=*/1, /*bottom=*/2, /*right=*/3, /*top=*/5);
71 
72   const CFX_Matrix kShearMatrix(1, 2, 0, 1, 0, 0);
73   EXPECT_TRUE(path.IsRect());
74   absl::optional<CFX_FloatRect> rect = path.GetRect(&kShearMatrix);
75   EXPECT_FALSE(rect.has_value());
76   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), path.GetBoundingBox());
77 
78   path.Transform(kShearMatrix);
79   EXPECT_FALSE(path.IsRect());
80   rect = path.GetRect(nullptr);
81   EXPECT_FALSE(rect.has_value());
82   EXPECT_EQ(CFX_FloatRect(1, 4, 3, 11), path.GetBoundingBox());
83 
84   const CFX_Matrix shear_inverse_matrix = kShearMatrix.GetInverse();
85   rect = path.GetRect(&shear_inverse_matrix);
86   ASSERT_TRUE(rect.has_value());
87   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), rect.value());
88   EXPECT_EQ(CFX_FloatRect(1, 4, 3, 11), path.GetBoundingBox());
89 
90   path.Transform(shear_inverse_matrix);
91   EXPECT_TRUE(path.IsRect());
92   rect = path.GetRect(nullptr);
93   ASSERT_TRUE(rect.has_value());
94   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), rect.value());
95   EXPECT_EQ(CFX_FloatRect(1, 2, 3, 5), path.GetBoundingBox());
96 }
97 
TEST(CFX_Path,Hexagon)98 TEST(CFX_Path, Hexagon) {
99   CFX_Path path;
100   path.AppendPoint({1, 0}, CFX_Path::Point::Type::kMove);
101   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
102   path.AppendPoint({3, 1}, CFX_Path::Point::Type::kLine);
103   path.AppendPoint({2, 2}, CFX_Path::Point::Type::kLine);
104   path.AppendPoint({1, 2}, CFX_Path::Point::Type::kLine);
105   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
106   ASSERT_EQ(6u, path.GetPoints().size());
107   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(5));
108   EXPECT_FALSE(path.IsClosingFigure(5));
109   EXPECT_FALSE(path.IsRect());
110   EXPECT_FALSE(path.GetRect(nullptr).has_value());
111   EXPECT_EQ(CFX_FloatRect(0, 0, 3, 2), path.GetBoundingBox());
112 
113   path.ClosePath();
114   ASSERT_EQ(6u, path.GetPoints().size());
115   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(5));
116   EXPECT_TRUE(path.IsClosingFigure(5));
117   EXPECT_FALSE(path.IsRect());
118   EXPECT_FALSE(path.GetRect(nullptr).has_value());
119 
120   // Calling ClosePath() repeatedly makes no difference.
121   path.ClosePath();
122   ASSERT_EQ(6u, path.GetPoints().size());
123   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(5));
124   EXPECT_TRUE(path.IsClosingFigure(5));
125   EXPECT_FALSE(path.IsRect());
126   EXPECT_FALSE(path.GetRect(nullptr).has_value());
127 
128   // A hexagon with the same start/end point is still not a rectangle.
129   path.Clear();
130   path.AppendPoint({1, 0}, CFX_Path::Point::Type::kMove);
131   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
132   path.AppendPoint({3, 1}, CFX_Path::Point::Type::kLine);
133   path.AppendPoint({2, 2}, CFX_Path::Point::Type::kLine);
134   path.AppendPoint({1, 2}, CFX_Path::Point::Type::kLine);
135   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
136   path.AppendPoint({1, 0}, CFX_Path::Point::Type::kLine);
137   EXPECT_FALSE(path.IsRect());
138   EXPECT_FALSE(path.GetRect(nullptr).has_value());
139   EXPECT_EQ(CFX_FloatRect(0, 0, 3, 2), path.GetBoundingBox());
140 }
141 
TEST(CFX_Path,ClosePath)142 TEST(CFX_Path, ClosePath) {
143   CFX_Path path;
144   path.AppendLine({0, 0}, {0, 1});
145   path.AppendLine({0, 1}, {1, 1});
146   path.AppendLine({1, 1}, {1, 0});
147   ASSERT_EQ(4u, path.GetPoints().size());
148   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(3));
149   EXPECT_FALSE(path.IsClosingFigure(3));
150   EXPECT_TRUE(path.IsRect());
151   absl::optional<CFX_FloatRect> rect = path.GetRect(nullptr);
152   ASSERT_TRUE(rect.has_value());
153   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
154 
155   const CFX_Matrix kIdentityMatrix;
156   ASSERT_TRUE(kIdentityMatrix.IsIdentity());
157   rect = path.GetRect(&kIdentityMatrix);
158   ASSERT_TRUE(rect.has_value());
159   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
160 
161   path.ClosePath();
162   ASSERT_EQ(4u, path.GetPoints().size());
163   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(3));
164   EXPECT_TRUE(path.IsClosingFigure(3));
165   EXPECT_TRUE(path.IsRect());
166   rect = path.GetRect(nullptr);
167   ASSERT_TRUE(rect.has_value());
168   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
169 
170   // Calling ClosePath() repeatedly makes no difference.
171   path.ClosePath();
172   ASSERT_EQ(4u, path.GetPoints().size());
173   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(3));
174   EXPECT_TRUE(path.IsClosingFigure(3));
175   EXPECT_TRUE(path.IsRect());
176   rect = path.GetRect(nullptr);
177   ASSERT_TRUE(rect.has_value());
178   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
179 
180   path.AppendPointAndClose({0, 0}, CFX_Path::Point::Type::kLine);
181   ASSERT_EQ(5u, path.GetPoints().size());
182   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(3));
183   EXPECT_TRUE(path.IsClosingFigure(3));
184   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(4));
185   EXPECT_TRUE(path.IsClosingFigure(4));
186   EXPECT_TRUE(path.IsRect());
187   rect = path.GetRect(nullptr);
188   ASSERT_TRUE(rect.has_value());
189   EXPECT_EQ(CFX_FloatRect(0, 0, 1, 1), rect.value());
190 }
191 
TEST(CFX_Path,FivePointRect)192 TEST(CFX_Path, FivePointRect) {
193   CFX_Path path;
194   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
195   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
196   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
197   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
198   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
199   ASSERT_EQ(5u, path.GetPoints().size());
200   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(4));
201   EXPECT_FALSE(path.IsClosingFigure(4));
202   EXPECT_TRUE(path.IsRect());
203   absl::optional<CFX_FloatRect> rect = path.GetRect(nullptr);
204   ASSERT_TRUE(rect.has_value());
205   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), rect.value());
206 
207   path.ClosePath();
208   ASSERT_EQ(5u, path.GetPoints().size());
209   EXPECT_EQ(CFX_Path::Point::Type::kLine, path.GetType(4));
210   EXPECT_TRUE(path.IsClosingFigure(4));
211   EXPECT_TRUE(path.IsRect());
212   rect = path.GetRect(nullptr);
213   ASSERT_TRUE(rect.has_value());
214   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), rect.value());
215 }
216 
TEST(CFX_Path,SixPlusPointRect)217 TEST(CFX_Path, SixPlusPointRect) {
218   CFX_Path path;
219   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
220   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
221   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
222   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
223   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
224   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
225   EXPECT_TRUE(path.IsRect());
226   absl::optional<CFX_FloatRect> rect = path.GetRect(nullptr);
227   ASSERT_TRUE(rect.has_value());
228   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), rect.value());
229   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
230 
231   path.Clear();
232   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
233   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
234   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
235   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
236   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
237   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
238   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
239   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
240   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
241   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
242   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
243   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
244   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
245   EXPECT_TRUE(path.IsRect());
246   rect = path.GetRect(nullptr);
247   ASSERT_TRUE(rect.has_value());
248   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), rect.value());
249   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
250 }
251 
TEST(CFX_Path,NotRect)252 TEST(CFX_Path, NotRect) {
253   CFX_Path path;
254   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
255   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
256   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
257   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
258   path.AppendPoint({0, 0.1f}, CFX_Path::Point::Type::kLine);
259   EXPECT_FALSE(path.IsRect());
260   absl::optional<CFX_FloatRect> rect = path.GetRect(nullptr);
261   EXPECT_FALSE(rect.has_value());
262   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
263 
264   path.ClosePath();
265   EXPECT_FALSE(path.IsRect());
266   rect = path.GetRect(nullptr);
267   EXPECT_FALSE(rect.has_value());
268   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
269 
270   path.Clear();
271   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
272   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
273   path.AppendPoint({3, 1}, CFX_Path::Point::Type::kLine);
274   path.AppendPointAndClose({0, 1}, CFX_Path::Point::Type::kLine);
275   EXPECT_FALSE(path.IsRect());
276   rect = path.GetRect(nullptr);
277   EXPECT_FALSE(rect.has_value());
278   EXPECT_EQ(CFX_FloatRect(0, 0, 3, 1), path.GetBoundingBox());
279 
280   path.Clear();
281   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
282   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
283   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
284   path.AppendPointAndClose({0, 1}, CFX_Path::Point::Type::kMove);
285   EXPECT_FALSE(path.IsRect());
286   rect = path.GetRect(nullptr);
287   EXPECT_FALSE(rect.has_value());
288   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
289 
290   path.Clear();
291   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
292   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
293   path.AppendPoint({3, 0}, CFX_Path::Point::Type::kLine);
294   path.AppendPointAndClose({0, 1}, CFX_Path::Point::Type::kLine);
295   EXPECT_FALSE(path.IsRect());
296   rect = path.GetRect(nullptr);
297   EXPECT_FALSE(rect.has_value());
298   EXPECT_EQ(CFX_FloatRect(0, 0, 3, 1), path.GetBoundingBox());
299 
300   path.Clear();
301   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
302   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
303   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
304   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
305   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
306   EXPECT_FALSE(path.IsRect());
307   rect = path.GetRect(nullptr);
308   EXPECT_FALSE(rect.has_value());
309   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
310 
311   path.Clear();
312   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
313   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
314   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
315   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
316   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
317   EXPECT_FALSE(path.IsRect());
318   rect = path.GetRect(nullptr);
319   EXPECT_FALSE(rect.has_value());
320   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 1), path.GetBoundingBox());
321 
322   path.Clear();
323   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
324   path.AppendPoint({2, 0}, CFX_Path::Point::Type::kLine);
325   path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
326   path.AppendPoint({2, 2}, CFX_Path::Point::Type::kLine);
327   EXPECT_FALSE(path.IsRect());
328   rect = path.GetRect(nullptr);
329   EXPECT_FALSE(rect.has_value());
330   const CFX_Matrix kScaleMatrix(1, 0, 0, 2, 60, 70);
331   rect = path.GetRect(&kScaleMatrix);
332   EXPECT_FALSE(rect.has_value());
333   EXPECT_EQ(CFX_FloatRect(0, 0, 2, 2), path.GetBoundingBox());
334 }
335 
TEST(CFX_Path,EmptyRect)336 TEST(CFX_Path, EmptyRect) {
337   // Document existing behavior where an empty rect is still considered a rect.
338   CFX_Path path;
339   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kMove);
340   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
341   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
342   path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
343   path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
344   EXPECT_TRUE(path.IsRect());
345   absl::optional<CFX_FloatRect> rect = path.GetRect(nullptr);
346   ASSERT_TRUE(rect.has_value());
347   EXPECT_EQ(CFX_FloatRect(0, 0, 0, 1), rect.value());
348   EXPECT_EQ(CFX_FloatRect(0, 0, 0, 1), path.GetBoundingBox());
349 }
350 
TEST(CFX_Path,Append)351 TEST(CFX_Path, Append) {
352   CFX_Path path;
353   path.AppendPoint({5, 6}, CFX_Path::Point::Type::kMove);
354   ASSERT_EQ(1u, path.GetPoints().size());
355   EXPECT_EQ(CFX_PointF(5, 6), path.GetPoint(0));
356 
357   CFX_Path empty_path;
358   path.Append(empty_path, nullptr);
359   ASSERT_EQ(1u, path.GetPoints().size());
360   EXPECT_EQ(CFX_PointF(5, 6), path.GetPoint(0));
361 
362   path.Append(path, nullptr);
363   ASSERT_EQ(2u, path.GetPoints().size());
364   EXPECT_EQ(CFX_PointF(5, 6), path.GetPoint(0));
365   EXPECT_EQ(CFX_PointF(5, 6), path.GetPoint(1));
366 
367   const CFX_Matrix kScaleMatrix(1, 0, 0, 2, 60, 70);
368   path.Append(path, &kScaleMatrix);
369   ASSERT_EQ(4u, path.GetPoints().size());
370   EXPECT_EQ(CFX_PointF(5, 6), path.GetPoint(0));
371   EXPECT_EQ(CFX_PointF(5, 6), path.GetPoint(1));
372   EXPECT_EQ(CFX_PointF(65, 82), path.GetPoint(2));
373   EXPECT_EQ(CFX_PointF(65, 82), path.GetPoint(3));
374 }
375 
TEST(CFX_Path,GetBoundingBoxForStrokePath)376 TEST(CFX_Path, GetBoundingBoxForStrokePath) {
377   static constexpr float kLineWidth = 1.0f;
378   static constexpr float kMiterLimit = 1.0f;
379 
380   {
381     // Test the case that the first/last point is "move" and it closes the
382     // paths.
383     CFX_Path path;
384     path.AppendPoint({2, 0}, CFX_Path::Point::Type::kMove);
385     path.ClosePath();
386     EXPECT_EQ(CFX_FloatRect(2, 0, 2, 0),
387               path.GetBoundingBoxForStrokePath(kLineWidth, kMiterLimit));
388   }
389 
390   {
391     // Test on a regular rect path.
392     CFX_Path path;
393     path.AppendPoint({2, 0}, CFX_Path::Point::Type::kMove);
394     path.AppendPoint({2, 1}, CFX_Path::Point::Type::kLine);
395     path.AppendPoint({0, 1}, CFX_Path::Point::Type::kLine);
396     path.AppendPoint({0, 0}, CFX_Path::Point::Type::kLine);
397     path.ClosePath();
398     EXPECT_EQ(CFX_FloatRect(-1, -1, 3, 2),
399               path.GetBoundingBoxForStrokePath(kLineWidth, kMiterLimit));
400 
401     // If the final point is "move" and the path remains open, it should not
402     // affect the bounding rect.
403     path.AppendPoint({20, 20}, CFX_Path::Point::Type::kMove);
404     EXPECT_EQ(CFX_FloatRect(-1, -1, 3, 2),
405               path.GetBoundingBoxForStrokePath(kLineWidth, kMiterLimit));
406   }
407 }
408