Home | History | Annotate | Download | only in fxgraphics
      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 
     12 CFX_Path::CFX_Path() {}
     13 
     14 CFX_Path::~CFX_Path() {}
     15 
     16 void CFX_Path::Clear() {
     17   data_.Clear();
     18 }
     19 
     20 void CFX_Path::Close() {
     21   data_.ClosePath();
     22 }
     23 
     24 void CFX_Path::MoveTo(const CFX_PointF& point) {
     25   data_.AppendPoint(point, FXPT_TYPE::MoveTo, false);
     26 }
     27 
     28 void CFX_Path::LineTo(const CFX_PointF& point) {
     29   data_.AppendPoint(point, FXPT_TYPE::LineTo, false);
     30 }
     31 
     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 
     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 
     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 
     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 
     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 
     88 void CFX_Path::AddEllipse(const CFX_RectF& rect) {
     89   AddArc(rect.TopLeft(), rect.Size(), 0, FX_PI * 2);
     90 }
     91 
     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 
    143 void CFX_Path::AddSubpath(CFX_Path* path) {
    144   if (!path)
    145     return;
    146   data_.Append(&path->data_, nullptr);
    147 }
    148 
    149 void CFX_Path::TransformBy(const CFX_Matrix& mt) {
    150   data_.Transform(&mt);
    151 }
    152