• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 #include "core/fxge/cfx_pathdata.h"
10 #include "third_party/base/ptr_util.h"
11 
CFX_Path()12 CFX_Path::CFX_Path() {}
13 
~CFX_Path()14 CFX_Path::~CFX_Path() {}
15 
Clear()16 void CFX_Path::Clear() {
17   data_.Clear();
18 }
19 
Close()20 void CFX_Path::Close() {
21   data_.ClosePath();
22 }
23 
MoveTo(const CFX_PointF & point)24 void CFX_Path::MoveTo(const CFX_PointF& point) {
25   data_.AppendPoint(point, FXPT_TYPE::MoveTo, false);
26 }
27 
LineTo(const CFX_PointF & point)28 void CFX_Path::LineTo(const CFX_PointF& point) {
29   data_.AppendPoint(point, FXPT_TYPE::LineTo, false);
30 }
31 
BezierTo(const CFX_PointF & c1,const CFX_PointF & c2,const CFX_PointF & to)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);
38 }
39 
ArcTo(const CFX_PointF & pos,const CFX_SizeF & size,FX_FLOAT start_angle,FX_FLOAT sweep_angle)40 void 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);
47 }
48 
ArcToInternal(const CFX_PointF & pos,const CFX_SizeF & size,FX_FLOAT start_angle,FX_FLOAT sweep_angle)49 void 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);
74 }
75 
AddLine(const CFX_PointF & p1,const CFX_PointF & p2)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);
79 }
80 
AddRectangle(FX_FLOAT left,FX_FLOAT top,FX_FLOAT width,FX_FLOAT height)81 void 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);
86 }
87 
AddEllipse(const CFX_RectF & rect)88 void CFX_Path::AddEllipse(const CFX_RectF& rect) {
89   AddArc(rect.TopLeft(), rect.Size(), 0, FX_PI * 2);
90 }
91 
AddArc(const CFX_PointF & original_pos,const CFX_SizeF & original_size,FX_FLOAT start_angle,FX_FLOAT sweep_angle)92 void 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);
141 }
142 
AddSubpath(CFX_Path * path)143 void CFX_Path::AddSubpath(CFX_Path* path) {
144   if (!path)
145     return;
146   data_.Append(&path->data_, nullptr);
147 }
148 
TransformBy(const CFX_Matrix & mt)149 void CFX_Path::TransformBy(const CFX_Matrix& mt) {
150   data_.Transform(&mt);
151 }
152