Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 1 | // Copyright 2016 PDFium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | |
| 7 | #include "xfa/fxgraphics/cfx_path.h" |
| 8 | |
dsinclair | 74a34fc | 2016-09-29 16:41:42 -0700 | [diff] [blame] | 9 | #include "core/fxge/cfx_pathdata.h" |
tsepez | a9caab9 | 2016-12-14 05:57:10 -0800 | [diff] [blame] | 10 | #include "third_party/base/ptr_util.h" |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 11 | |
weili | 16fccc5 | 2016-08-09 10:33:10 -0700 | [diff] [blame] | 12 | CFX_Path::CFX_Path() {} |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 13 | |
weili | 16fccc5 | 2016-08-09 10:33:10 -0700 | [diff] [blame] | 14 | CFX_Path::~CFX_Path() {} |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 15 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 16 | void CFX_Path::Clear() { |
| 17 | data_.Clear(); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 18 | } |
| 19 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 20 | void CFX_Path::Close() { |
| 21 | data_.ClosePath(); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 22 | } |
| 23 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 24 | void CFX_Path::MoveTo(const CFX_PointF& point) { |
| 25 | data_.AppendPoint(point, FXPT_TYPE::MoveTo, false); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 26 | } |
| 27 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 28 | void CFX_Path::LineTo(const CFX_PointF& point) { |
| 29 | data_.AppendPoint(point, FXPT_TYPE::LineTo, false); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 30 | } |
| 31 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 32 | void CFX_Path::BezierTo(const CFX_PointF& c1, |
| 33 | const CFX_PointF& c2, |
| 34 | const CFX_PointF& to) { |
| 35 | data_.AppendPoint(c1, FXPT_TYPE::BezierTo, false); |
| 36 | data_.AppendPoint(c2, FXPT_TYPE::BezierTo, false); |
| 37 | data_.AppendPoint(to, FXPT_TYPE::BezierTo, false); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 38 | } |
| 39 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 40 | void CFX_Path::ArcTo(const CFX_PointF& pos, |
| 41 | const CFX_SizeF& size, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 42 | float start_angle, |
| 43 | float sweep_angle) { |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 44 | CFX_SizeF new_size = size / 2.0f; |
| 45 | ArcToInternal(CFX_PointF(pos.x + new_size.width, pos.y + new_size.height), |
| 46 | new_size, start_angle, sweep_angle); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 47 | } |
| 48 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 49 | void CFX_Path::ArcToInternal(const CFX_PointF& pos, |
| 50 | const CFX_SizeF& size, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 51 | float start_angle, |
| 52 | float sweep_angle) { |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame^] | 53 | float x0 = cos(sweep_angle / 2); |
| 54 | float y0 = sin(sweep_angle / 2); |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 55 | float tx = ((1.0f - x0) * 4) / (3 * 1.0f); |
| 56 | float ty = y0 - ((tx * x0) / y0); |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 57 | |
| 58 | CFX_PointF points[] = {CFX_PointF(x0 + tx, -ty), CFX_PointF(x0 + tx, ty)}; |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame^] | 59 | float sn = sin(start_angle + sweep_angle / 2); |
| 60 | float cs = cos(start_angle + sweep_angle / 2); |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 61 | |
| 62 | CFX_PointF bezier; |
| 63 | bezier.x = pos.x + (size.width * ((points[0].x * cs) - (points[0].y * sn))); |
| 64 | bezier.y = pos.y + (size.height * ((points[0].x * sn) + (points[0].y * cs))); |
| 65 | data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false); |
| 66 | |
| 67 | bezier.x = pos.x + (size.width * ((points[1].x * cs) - (points[1].y * sn))); |
| 68 | bezier.y = pos.y + (size.height * ((points[1].x * sn) + (points[1].y * cs))); |
| 69 | data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false); |
| 70 | |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame^] | 71 | bezier.x = pos.x + (size.width * cos(start_angle + sweep_angle)); |
| 72 | bezier.y = pos.y + (size.height * sin(start_angle + sweep_angle)); |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 73 | data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 74 | } |
| 75 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 76 | void CFX_Path::AddLine(const CFX_PointF& p1, const CFX_PointF& p2) { |
| 77 | data_.AppendPoint(p1, FXPT_TYPE::MoveTo, false); |
| 78 | data_.AppendPoint(p2, FXPT_TYPE::LineTo, false); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 79 | } |
| 80 | |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 81 | void CFX_Path::AddRectangle(float left, float top, float width, float height) { |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 82 | data_.AppendRect(left, top, left + width, top + height); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 83 | } |
| 84 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 85 | void CFX_Path::AddEllipse(const CFX_RectF& rect) { |
| 86 | AddArc(rect.TopLeft(), rect.Size(), 0, FX_PI * 2); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 87 | } |
| 88 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 89 | void CFX_Path::AddArc(const CFX_PointF& original_pos, |
| 90 | const CFX_SizeF& original_size, |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 91 | float start_angle, |
| 92 | float sweep_angle) { |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 93 | if (sweep_angle == 0) |
| 94 | return; |
| 95 | |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 96 | const float bezier_arc_angle_epsilon = 0.01f; |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 97 | while (start_angle > FX_PI * 2) |
| 98 | start_angle -= FX_PI * 2; |
| 99 | while (start_angle < 0) |
| 100 | start_angle += FX_PI * 2; |
| 101 | if (sweep_angle >= FX_PI * 2) |
| 102 | sweep_angle = FX_PI * 2; |
| 103 | if (sweep_angle <= -FX_PI * 2) |
| 104 | sweep_angle = -FX_PI * 2; |
| 105 | |
| 106 | CFX_SizeF size = original_size / 2; |
| 107 | CFX_PointF pos(original_pos.x + size.width, original_pos.y + size.height); |
Dan Sinclair | 669a418 | 2017-04-03 14:51:45 -0400 | [diff] [blame^] | 108 | data_.AppendPoint(pos + CFX_PointF(size.width * cos(start_angle), |
| 109 | size.height * sin(start_angle)), |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 110 | FXPT_TYPE::MoveTo, false); |
| 111 | |
Dan Sinclair | 05df075 | 2017-03-14 14:43:42 -0400 | [diff] [blame] | 112 | float total_sweep = 0; |
| 113 | float local_sweep = 0; |
| 114 | float prev_sweep = 0; |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 115 | bool done = false; |
| 116 | do { |
| 117 | if (sweep_angle < 0) { |
| 118 | prev_sweep = total_sweep; |
| 119 | local_sweep = -FX_PI / 2; |
| 120 | total_sweep -= FX_PI / 2; |
| 121 | if (total_sweep <= sweep_angle + bezier_arc_angle_epsilon) { |
| 122 | local_sweep = sweep_angle - prev_sweep; |
| 123 | done = true; |
| 124 | } |
| 125 | } else { |
| 126 | prev_sweep = total_sweep; |
| 127 | local_sweep = FX_PI / 2; |
| 128 | total_sweep += FX_PI / 2; |
| 129 | if (total_sweep >= sweep_angle - bezier_arc_angle_epsilon) { |
| 130 | local_sweep = sweep_angle - prev_sweep; |
| 131 | done = true; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | ArcToInternal(pos, size, start_angle, local_sweep); |
| 136 | start_angle += local_sweep; |
| 137 | } while (!done); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 138 | } |
| 139 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 140 | void CFX_Path::AddSubpath(CFX_Path* path) { |
| 141 | if (!path) |
| 142 | return; |
| 143 | data_.Append(&path->data_, nullptr); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 144 | } |
| 145 | |
Dan Sinclair | efcf362 | 2017-02-23 13:29:56 -0500 | [diff] [blame] | 146 | void CFX_Path::TransformBy(const CFX_Matrix& mt) { |
| 147 | data_.Transform(&mt); |
Dan Sinclair | 811b8a4 | 2016-03-17 08:59:42 -0400 | [diff] [blame] | 148 | } |