blob: fc0051ad4cb846ef76db7b9acc9e26369501d7d9 [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,
Dan Sinclair05df0752017-03-14 14:43:42 -040042 float start_angle,
43 float sweep_angle) {
Dan Sinclairefcf3622017-02-23 13:29:56 -050044 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,
Dan Sinclair05df0752017-03-14 14:43:42 -040051 float start_angle,
52 float sweep_angle) {
Dan Sinclair669a4182017-04-03 14:51:45 -040053 float x0 = cos(sweep_angle / 2);
54 float y0 = sin(sweep_angle / 2);
Dan Sinclair05df0752017-03-14 14:43:42 -040055 float tx = ((1.0f - x0) * 4) / (3 * 1.0f);
56 float ty = y0 - ((tx * x0) / y0);
Dan Sinclairefcf3622017-02-23 13:29:56 -050057
58 CFX_PointF points[] = {CFX_PointF(x0 + tx, -ty), CFX_PointF(x0 + tx, ty)};
Dan Sinclair669a4182017-04-03 14:51:45 -040059 float sn = sin(start_angle + sweep_angle / 2);
60 float cs = cos(start_angle + sweep_angle / 2);
Dan Sinclairefcf3622017-02-23 13:29:56 -050061
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 Sinclair669a4182017-04-03 14:51:45 -040071 bezier.x = pos.x + (size.width * cos(start_angle + sweep_angle));
72 bezier.y = pos.y + (size.height * sin(start_angle + sweep_angle));
Dan Sinclairefcf3622017-02-23 13:29:56 -050073 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 Sinclair05df0752017-03-14 14:43:42 -040081void CFX_Path::AddRectangle(float left, float top, float width, float height) {
Dan Sinclairefcf3622017-02-23 13:29:56 -050082 data_.AppendRect(left, top, left + width, top + height);
Dan Sinclair811b8a42016-03-17 08:59:42 -040083}
84
Dan Sinclairefcf3622017-02-23 13:29:56 -050085void CFX_Path::AddEllipse(const CFX_RectF& rect) {
86 AddArc(rect.TopLeft(), rect.Size(), 0, FX_PI * 2);
Dan Sinclair811b8a42016-03-17 08:59:42 -040087}
88
Dan Sinclairefcf3622017-02-23 13:29:56 -050089void CFX_Path::AddArc(const CFX_PointF& original_pos,
90 const CFX_SizeF& original_size,
Dan Sinclair05df0752017-03-14 14:43:42 -040091 float start_angle,
92 float sweep_angle) {
Dan Sinclairefcf3622017-02-23 13:29:56 -050093 if (sweep_angle == 0)
94 return;
95
Dan Sinclair05df0752017-03-14 14:43:42 -040096 const float bezier_arc_angle_epsilon = 0.01f;
Dan Sinclairefcf3622017-02-23 13:29:56 -050097 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 Sinclair669a4182017-04-03 14:51:45 -0400108 data_.AppendPoint(pos + CFX_PointF(size.width * cos(start_angle),
109 size.height * sin(start_angle)),
Dan Sinclairefcf3622017-02-23 13:29:56 -0500110 FXPT_TYPE::MoveTo, false);
111
Dan Sinclair05df0752017-03-14 14:43:42 -0400112 float total_sweep = 0;
113 float local_sweep = 0;
114 float prev_sweep = 0;
Dan Sinclairefcf3622017-02-23 13:29:56 -0500115 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 Sinclair811b8a42016-03-17 08:59:42 -0400138}
139
Dan Sinclairefcf3622017-02-23 13:29:56 -0500140void CFX_Path::AddSubpath(CFX_Path* path) {
141 if (!path)
142 return;
143 data_.Append(&path->data_, nullptr);
Dan Sinclair811b8a42016-03-17 08:59:42 -0400144}
145
Dan Sinclairefcf3622017-02-23 13:29:56 -0500146void CFX_Path::TransformBy(const CFX_Matrix& mt) {
147 data_.Transform(&mt);
Dan Sinclair811b8a42016-03-17 08:59:42 -0400148}