Add helper functions in CFX_PathData::GetZeroAreaPath(). Create helper function CheckSimpleLinePath() which handles 3-point simple line path and CheckPalindromicPath() which handles palindromic path in CFX_PathData::GetZeroAreaPath(). Bug: pdfium:1638 Change-Id: I98c298df04c65a626a0d9cbc9c6f0804993d511a Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/77873 Commit-Queue: Hui Yingst <nigi@chromium.org> Reviewed-by: Daniel Hosseinian <dhoss@chromium.org>
diff --git a/core/fxge/cfx_pathdata.cpp b/core/fxge/cfx_pathdata.cpp index 7e08205..682fc56 100644 --- a/core/fxge/cfx_pathdata.cpp +++ b/core/fxge/cfx_pathdata.cpp
@@ -12,6 +12,77 @@ namespace { +// Returns true if the simple path contains 3 points which draw a line from +// A->B->A and form a zero area. +bool CheckSimpleLinePath(const std::vector<FX_PATHPOINT>& points, + const CFX_Matrix* matrix, + bool adjust, + CFX_PathData* new_path, + bool* thin, + bool* set_identity) { + if (points.size() != 3) + return false; + + if (points[0].m_Type != FXPT_TYPE::MoveTo || + points[1].m_Type != FXPT_TYPE::LineTo || + points[2].m_Type != FXPT_TYPE::LineTo || + points[0].m_Point != points[2].m_Point) { + return false; + } + + for (size_t i = 0; i < 2; i++) { + CFX_PointF point = points[i].m_Point; + if (adjust) { + if (matrix) + point = matrix->Transform(point); + + point = CFX_PointF(static_cast<int>(point.x) + 0.5f, + static_cast<int>(point.y) + 0.5f); + } + new_path->AppendPoint(point, + i == 0 ? FXPT_TYPE::MoveTo : FXPT_TYPE::LineTo); + } + if (adjust && matrix) + *set_identity = true; + + // Note, both x and y coordinates of the end points need to be different. + if (points[0].m_Point.x != points[1].m_Point.x && + points[0].m_Point.y != points[1].m_Point.y) { + *thin = true; + } + return true; +} + +// Returns true if `points` is palindromic and forms zero area. Otherwise, +// returns false. +bool CheckPalindromicPath(const std::vector<FX_PATHPOINT>& points, + CFX_PathData* new_path, + bool* thin) { + if (points.size() <= 3 || !(points.size() % 2)) + return false; + + const int mid = points.size() / 2; + bool zero_area = true; + CFX_PathData temp_path; + for (int i = 0; i < mid; i++) { + if (!(points[mid - i - 1].m_Point == points[mid + i + 1].m_Point && + points[mid - i - 1].m_Type != FXPT_TYPE::BezierTo && + points[mid + i + 1].m_Type != FXPT_TYPE::BezierTo)) { + zero_area = false; + break; + } + + temp_path.AppendPoint(points[mid - i].m_Point, FXPT_TYPE::MoveTo); + temp_path.AppendPoint(points[mid - i - 1].m_Point, FXPT_TYPE::LineTo); + } + if (!zero_area) + return false; + + new_path->Append(&temp_path, nullptr); + *thin = true; + return true; +} + bool IsFoldingVerticalLine(const CFX_PointF& a, const CFX_PointF& b, const CFX_PointF& c) { @@ -327,57 +398,19 @@ bool* thin, bool* set_identity) const { *set_identity = false; + + // TODO(crbug.com/pdfium/1639): Need to handle the case when there are + // only 2 points in the path that forms a zero area. if (m_Points.size() < 3) return false; - if (m_Points.size() == 3 && m_Points[0].m_Type == FXPT_TYPE::MoveTo && - m_Points[1].m_Type == FXPT_TYPE::LineTo && - m_Points[2].m_Type == FXPT_TYPE::LineTo && - m_Points[0].m_Point == m_Points[2].m_Point) { - for (size_t i = 0; i < 2; i++) { - CFX_PointF point = m_Points[i].m_Point; - if (adjust) { - if (matrix) - point = matrix->Transform(point); - - point = CFX_PointF(static_cast<int>(point.x) + 0.5f, - static_cast<int>(point.y) + 0.5f); - } - new_path->AppendPoint(point, - i == 0 ? FXPT_TYPE::MoveTo : FXPT_TYPE::LineTo); - } - if (adjust && matrix) - *set_identity = true; - - // Note, they both have to be not equal. - if (m_Points[0].m_Point.x != m_Points[1].m_Point.x && - m_Points[0].m_Point.y != m_Points[1].m_Point.y) { - *thin = true; - } + if (CheckSimpleLinePath(m_Points, matrix, adjust, new_path, thin, + set_identity)) { return true; } - if (((m_Points.size() > 3) && (m_Points.size() % 2))) { - int mid = m_Points.size() / 2; - bool zero_area = true; - CFX_PathData temp_path; - for (int i = 0; i < mid; i++) { - if (!(m_Points[mid - i - 1].m_Point == m_Points[mid + i + 1].m_Point && - m_Points[mid - i - 1].m_Type != FXPT_TYPE::BezierTo && - m_Points[mid + i + 1].m_Type != FXPT_TYPE::BezierTo)) { - zero_area = false; - break; - } - - temp_path.AppendPoint(m_Points[mid - i].m_Point, FXPT_TYPE::MoveTo); - temp_path.AppendPoint(m_Points[mid - i - 1].m_Point, FXPT_TYPE::LineTo); - } - if (zero_area) { - new_path->Append(&temp_path, nullptr); - *thin = true; - return true; - } - } + if (CheckPalindromicPath(m_Points, new_path, thin)) + return true; int start_point = 0; for (size_t i = 0; i < m_Points.size(); i++) {