7#include "core/fxge/cfx_path.h"
15#include "core/fxcrt/check_op.h"
16#include "core/fxcrt/fx_system.h"
20bool IsRectPreTransform(
const std::vector<CFX_Path::Point>& points) {
21 if (points.size() != 5 && points.size() != 4)
24 if (points.size() == 5 && points[0].m_Point != points[4].m_Point)
27 if (points[0].m_Point == points[2].m_Point ||
28 points[1].m_Point == points[3].m_Point) {
32 for (size_t i = 1; i < points.size(); ++i) {
40 return p1.x != p2.x && p1.y != p2.y;
43bool IsRectImpl(
const std::vector<CFX_Path::Point>& points) {
44 if (!IsRectPreTransform(points))
47 for (
int i = 1; i < 4; i++) {
48 if (XYBothNotEqual(points[i].m_Point, points[i - 1].m_Point))
52 if (XYBothNotEqual(points[0].m_Point, points[3].m_Point))
64bool PathPointsNeedNormalization(
const std::vector<CFX_Path::Point>& points) {
65 return points.size() > 5;
68std::vector<CFX_Path::Point> GetNormalizedPoints(
69 const std::vector<CFX_Path::Point>& points) {
70 DCHECK(PathPointsNeedNormalization(points));
72 if (points[0].m_Point != points.back().m_Point)
75 std::vector<CFX_Path::Point> normalized;
76 normalized.reserve(6);
77 normalized.push_back(points[0]);
78 for (
auto it = points.begin() + 1; it != points.end(); ++it) {
80 if (normalized.size() +
std::distance(it, points.end()) == 5) {
81 std::copy(it, points.end(),
std::back_inserter(normalized));
86 const auto& point = *it;
88 !normalized.back().m_CloseFigure &&
89 point.m_Point == normalized.back().m_Point) {
93 normalized.push_back(point);
96 if (normalized.size() > 5)
108 if (start_pos.x == end_pos.x) {
109 if (start_pos.y == end_pos.y) {
116 if (end_pos.y < start_pos.y)
117 point_y = end_pos.y - hw;
119 point_y = end_pos.y + hw;
126 if (start_pos.y == end_pos.y) {
128 if (end_pos.x < start_pos.x)
129 point_x = end_pos.x - hw;
131 point_x = end_pos.x + hw;
139 float ll = hypotf(diff.x, diff.y);
140 float mx = end_pos.x + hw * diff.x / ll;
141 float my = end_pos.y + hw * diff.y / ll;
142 float dx1 = hw * diff.y / ll;
143 float dy1 = hw * diff.x / ll;
162 float one_twentieth = 1.0f / 20;
164 bool bStartVert = fabs(start_pos.x - mid_pos.x) < one_twentieth;
165 bool bEndVert = fabs(mid_pos.x - end_pos.x) < one_twentieth;
166 if (bStartVert && bEndVert) {
167 int start_dir = mid_pos.y > start_pos.y ? 1 : -1;
168 float point_y = mid_pos.y + half_width * start_dir;
175 CFX_PointF start_to_mid = start_pos - mid_pos;
176 start_k = (mid_pos.y - start_pos.y) / (mid_pos.x - start_pos.x);
177 start_c = mid_pos.y - (start_k * mid_pos.x);
178 start_len = hypotf(start_to_mid.x, start_to_mid.y);
179 start_dc = fabsf(half_width * start_len / start_to_mid.x);
183 end_k = end_to_mid.y / end_to_mid.x;
184 end_c = mid_pos.y - (end_k * mid_pos.x);
185 end_len = hypotf(end_to_mid.x, end_to_mid.y);
186 end_dc = fabs(half_width * end_len / end_to_mid.x);
190 if (end_pos.x < start_pos.x)
191 outside.x += half_width;
193 outside.x -= half_width;
195 if (start_pos.y < (end_k * start_pos.x) + end_c)
196 outside.y = (end_k * outside.x) + end_c + end_dc;
198 outside.y = (end_k * outside.x) + end_c - end_dc;
206 if (start_pos.x < end_pos.x)
207 outside.x += half_width;
209 outside.x -= half_width;
211 if (end_pos.y < (start_k * end_pos.x) + start_c)
212 outside.y = (start_k * outside.x) + start_c + start_dc;
214 outside.y = (start_k * outside.x) + start_c - start_dc;
220 if (fabs(start_k - end_k) < one_twentieth) {
221 int start_dir = mid_pos.x > start_pos.x ? 1 : -1;
222 int end_dir = end_pos.x > mid_pos.x ? 1 : -1;
223 if (start_dir == end_dir)
224 UpdateLineEndPoints(rect, mid_pos, end_pos, half_width);
226 UpdateLineEndPoints(rect, start_pos, mid_pos, half_width);
230 float start_outside_c = start_c;
231 if (end_pos.y < (start_k * end_pos.x) + start_c)
232 start_outside_c += start_dc;
234 start_outside_c -= start_dc;
236 float end_outside_c = end_c;
237 if (start_pos.y < (end_k * start_pos.x) + end_c)
238 end_outside_c += end_dc;
240 end_outside_c -= end_dc;
242 float join_x = (end_outside_c - start_outside_c) / (start_k - end_k);
243 float join_y = start_k * join_x + start_outside_c;
271 if (m_Points.empty())
273 m_Points.back().m_CloseFigure =
true;
277 if (src.m_Points.empty())
280 size_t cur_size = m_Points.size();
281 m_Points.insert(m_Points.end(), src.m_Points.begin(), src.m_Points.end());
286 for (size_t i = cur_size; i < m_Points.size(); i++)
287 m_Points[i].m_Point = matrix->Transform(m_Points[i].m_Point);
291 m_Points.emplace_back(point, type,
false);
295 m_Points.emplace_back(point, type,
true);
299 if (m_Points.empty() || fabs(m_Points.back().m_Point.x - pt1.x) > 0.001 ||
300 fabs(m_Points.back().m_Point.y - pt1.y) > 0.001) {
324 if (m_Points.empty())
328 for (size_t i = 1; i < m_Points.size(); ++i)
329 rect.UpdateRect(m_Points[i].m_Point);
334 float miter_limit)
const {
337 float half_width = line_width;
338 size_t iStartPoint = 0;
339 size_t iEndPoint = 0;
340 size_t iMiddlePoint = 0;
342 while (iPoint < m_Points.size()) {
343 if (m_Points[iPoint].m_Type == CFX_Path::Point::Type::kMove) {
344 if (iPoint + 1 == m_Points.size()) {
345 if (m_Points[iPoint].m_CloseFigure) {
347 rect.UpdateRect(m_Points[iPoint].m_Point);
352 iStartPoint = iPoint + 1;
356 if (m_Points[iPoint].IsTypeAndOpen(CFX_Path::Point::Type::kBezier)) {
358 CHECK_LT(iPoint + 2, m_Points.size());
359 DCHECK_EQ(m_Points[iPoint + 1].m_Type, CFX_Path::Point::Type::kBezier);
360 DCHECK_EQ(m_Points[iPoint + 2].m_Type, CFX_Path::Point::Type::kBezier);
361 rect.UpdateRect(m_Points[iPoint].m_Point);
362 rect.UpdateRect(m_Points[iPoint + 1].m_Point);
365 if (iPoint + 1 == m_Points.size() ||
366 m_Points[iPoint + 1].m_Type == CFX_Path::Point::Type::kMove) {
367 iStartPoint = iPoint - 1;
371 iStartPoint = iPoint - 1;
372 iMiddlePoint = iPoint;
373 iEndPoint = iPoint + 1;
377 CHECK_LT(iStartPoint, m_Points.size());
378 CHECK_LT(iEndPoint, m_Points.size());
380 CHECK_LT(iMiddlePoint, m_Points.size());
381 UpdateLineJoinPoints(
382 &rect, m_Points[iStartPoint].m_Point, m_Points[iMiddlePoint].m_Point,
383 m_Points[iEndPoint].m_Point, half_width, miter_limit);
385 UpdateLineEndPoints(&rect, m_Points[iStartPoint].m_Point,
386 m_Points[iEndPoint].m_Point, half_width);
394 for (
auto& point : m_Points)
395 point.m_Point = matrix.Transform(point.m_Point);
399 if (PathPointsNeedNormalization(m_Points))
400 return IsRectImpl(GetNormalizedPoints(m_Points));
401 return IsRectImpl(m_Points);
405 bool do_normalize = PathPointsNeedNormalization(m_Points);
406 std::vector<Point> normalized;
408 normalized = GetNormalizedPoints(m_Points);
409 const std::vector<Point>& path_points = do_normalize ? normalized : m_Points;
412 if (!IsRectImpl(path_points))
415 return CreateRectFromPoints(path_points[0].m_Point, path_points[2].m_Point);
418 if (!IsRectPreTransform(path_points))
422 for (size_t i = 0; i < path_points.size(); ++i) {
427 if (XYBothNotEqual(points[i], points[i - 1]))
431 if (XYBothNotEqual(points[0], points[3]))
434 return CreateRectFromPoints(points[0], points[2]);
437CFX_RetainablePath::CFX_RetainablePath() =
default;
444CFX_RetainablePath::CFX_RetainablePath(
const CFX_RetainablePath& src)
450 return pdfium::MakeRetain<CFX_RetainablePath>(*
this);
constexpr CFX_FloatRect(float l, float b, float r, float t)
constexpr CFX_FloatRect()=default
void UpdateRect(const CFX_PointF &point)
CFX_PointF Transform(const CFX_PointF &point) const
Point(const CFX_PointF &point, Type type, bool close)
Point(const Point &other)
CFX_FloatRect GetBoundingBox() const
void Transform(const CFX_Matrix &matrix)
void AppendRect(float left, float bottom, float right, float top)
CFX_Path(CFX_Path &&src) noexcept
void Append(const CFX_Path &src, const CFX_Matrix *matrix)
CFX_FloatRect GetBoundingBoxForStrokePath(float line_width, float miter_limit) const
void AppendFloatRect(const CFX_FloatRect &rect)
void AppendPointAndClose(const CFX_PointF &point, Point::Type type)
void AppendLine(const CFX_PointF &pt1, const CFX_PointF &pt2)
CFX_Path(const CFX_Path &src)
std::optional< CFX_FloatRect > GetRect(const CFX_Matrix *matrix) const
void AppendPoint(const CFX_PointF &point, Point::Type type)
~CFX_RetainablePath() override
RetainPtr< CFX_RetainablePath > Clone() const
CFX_PTemplate< float > CFX_PointF