blob: d56eb13f6741f7f931f2fffc4b447b59bad3a5a9 [file] [log] [blame]
Dan Sinclair811b8a42016-03-17 08:59:42 -04001// 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
dsinclair74a34fc2016-09-29 16:41:42 -07009#include "core/fxge/cfx_pathdata.h"
tsepeza9caab92016-12-14 05:57:10 -080010#include "third_party/base/ptr_util.h"
Dan Sinclair811b8a42016-03-17 08:59:42 -040011
weili16fccc52016-08-09 10:33:10 -070012CFX_Path::CFX_Path() {}
Dan Sinclair811b8a42016-03-17 08:59:42 -040013
weili16fccc52016-08-09 10:33:10 -070014CFX_Path::~CFX_Path() {}
Dan Sinclair811b8a42016-03-17 08:59:42 -040015
Dan Sinclairefcf3622017-02-23 13:29:56 -050016void CFX_Path::Clear() {
17 data_.Clear();
Dan Sinclair811b8a42016-03-17 08:59:42 -040018}
19
Dan Sinclairefcf3622017-02-23 13:29:56 -050020void CFX_Path::Close() {
21 data_.ClosePath();
Dan Sinclair811b8a42016-03-17 08:59:42 -040022}
23
Dan Sinclairefcf3622017-02-23 13:29:56 -050024void CFX_Path::MoveTo(const CFX_PointF& point) {
25 data_.AppendPoint(point, FXPT_TYPE::MoveTo, false);
Dan Sinclair811b8a42016-03-17 08:59:42 -040026}
27
Dan Sinclairefcf3622017-02-23 13:29:56 -050028void CFX_Path::LineTo(const CFX_PointF& point) {
29 data_.AppendPoint(point, FXPT_TYPE::LineTo, false);
Dan Sinclair811b8a42016-03-17 08:59:42 -040030}
31
Dan Sinclairefcf3622017-02-23 13:29:56 -050032void 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 Sinclair811b8a42016-03-17 08:59:42 -040038}
39
Dan Sinclairefcf3622017-02-23 13:29:56 -050040void CFX_Path::ArcTo(const CFX_PointF& pos,
41 const CFX_SizeF& size,
42 FX_FLOAT start_angle,
43 FX_FLOAT sweep_angle) {
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 Sinclair811b8a42016-03-17 08:59:42 -040047}
48
Dan Sinclairefcf3622017-02-23 13:29:56 -050049void CFX_Path::ArcToInternal(const CFX_PointF& pos,
50 const CFX_SizeF& size,
51 FX_FLOAT start_angle,
52 FX_FLOAT sweep_angle) {
53 FX_FLOAT x0 = FXSYS_cos(sweep_angle / 2);
54 FX_FLOAT y0 = FXSYS_sin(sweep_angle / 2);
55 FX_FLOAT tx = ((1.0f - x0) * 4) / (3 * 1.0f);
56 FX_FLOAT ty = y0 - ((tx * x0) / y0);
57
58 CFX_PointF points[] = {CFX_PointF(x0 + tx, -ty), CFX_PointF(x0 + tx, ty)};
59 FX_FLOAT sn = FXSYS_sin(start_angle + sweep_angle / 2);
60 FX_FLOAT cs = FXSYS_cos(start_angle + sweep_angle / 2);
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
71 bezier.x = pos.x + (size.width * FXSYS_cos(start_angle + sweep_angle));
72 bezier.y = pos.y + (size.height * FXSYS_sin(start_angle + sweep_angle));
73 data_.AppendPoint(bezier, FXPT_TYPE::BezierTo, false);
Dan Sinclair811b8a42016-03-17 08:59:42 -040074}
75
Dan Sinclairefcf3622017-02-23 13:29:56 -050076void 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 Sinclair811b8a42016-03-17 08:59:42 -040079}
80
Dan Sinclairefcf3622017-02-23 13:29:56 -050081void CFX_Path::AddRectangle(FX_FLOAT left,
82 FX_FLOAT top,
83 FX_FLOAT width,
84 FX_FLOAT height) {
85 data_.AppendRect(left, top, left + width, top + height);
Dan Sinclair811b8a42016-03-17 08:59:42 -040086}
87
Dan Sinclairefcf3622017-02-23 13:29:56 -050088void CFX_Path::AddEllipse(const CFX_RectF& rect) {
89 AddArc(rect.TopLeft(), rect.Size(), 0, FX_PI * 2);
Dan Sinclair811b8a42016-03-17 08:59:42 -040090}
91
Dan Sinclairefcf3622017-02-23 13:29:56 -050092void CFX_Path::AddArc(const CFX_PointF& original_pos,
93 const CFX_SizeF& original_size,
94 FX_FLOAT start_angle,
95 FX_FLOAT sweep_angle) {
96 if (sweep_angle == 0)
97 return;
98
99 const FX_FLOAT bezier_arc_angle_epsilon = 0.01f;
100 while (start_angle > FX_PI * 2)
101 start_angle -= FX_PI * 2;
102 while (start_angle < 0)
103 start_angle += FX_PI * 2;
104 if (sweep_angle >= FX_PI * 2)
105 sweep_angle = FX_PI * 2;
106 if (sweep_angle <= -FX_PI * 2)
107 sweep_angle = -FX_PI * 2;
108
109 CFX_SizeF size = original_size / 2;
110 CFX_PointF pos(original_pos.x + size.width, original_pos.y + size.height);
111 data_.AppendPoint(pos + CFX_PointF(size.width * FXSYS_cos(start_angle),
112 size.height * FXSYS_sin(start_angle)),
113 FXPT_TYPE::MoveTo, false);
114
115 FX_FLOAT total_sweep = 0;
116 FX_FLOAT local_sweep = 0;
117 FX_FLOAT prev_sweep = 0;
118 bool done = false;
119 do {
120 if (sweep_angle < 0) {
121 prev_sweep = total_sweep;
122 local_sweep = -FX_PI / 2;
123 total_sweep -= FX_PI / 2;
124 if (total_sweep <= sweep_angle + bezier_arc_angle_epsilon) {
125 local_sweep = sweep_angle - prev_sweep;
126 done = true;
127 }
128 } else {
129 prev_sweep = total_sweep;
130 local_sweep = FX_PI / 2;
131 total_sweep += FX_PI / 2;
132 if (total_sweep >= sweep_angle - bezier_arc_angle_epsilon) {
133 local_sweep = sweep_angle - prev_sweep;
134 done = true;
135 }
136 }
137
138 ArcToInternal(pos, size, start_angle, local_sweep);
139 start_angle += local_sweep;
140 } while (!done);
Dan Sinclair811b8a42016-03-17 08:59:42 -0400141}
142
Dan Sinclairefcf3622017-02-23 13:29:56 -0500143void CFX_Path::AddSubpath(CFX_Path* path) {
144 if (!path)
145 return;
146 data_.Append(&path->data_, nullptr);
Dan Sinclair811b8a42016-03-17 08:59:42 -0400147}
148
Dan Sinclairefcf3622017-02-23 13:29:56 -0500149void CFX_Path::TransformBy(const CFX_Matrix& mt) {
150 data_.Transform(&mt);
Dan Sinclair811b8a42016-03-17 08:59:42 -0400151}