Move GetZeroAreaPath() to core/fxge/cfx_renderdevice.cpp. In CFX_RenderDevice::DrawPathWithBlend(), to process each sub path from `pPathData`, we will need to form every sub path in that same function and use GetZeroAreaPath() to calculate its zero areas before drawing. This requires GetZeroAreaPath() taking any vector of FX_PATHPOINT as a path and processing it, instead of processing all the points of `pPathData`. Therefore GetZeroAreaPath() no longer needs to be a member of CFX_PathDataon. This CL makes GetZeroAreaPath() take a pdfium::span<const FX_PATHPOINT> as an input parameter, and moves it and its helper functions to the anonymous namespace in core/fxge/cfx_renderdevice.cpp. Also changes the helpers take pdfium::span<> instead of std::vector as inputs. Bug: pdfium:1638 Change-Id: Ia07cbb261a09bd002ed56b976d450ed2951c9cc9 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/77970 Commit-Queue: Hui Yingst <nigi@chromium.org> Reviewed-by: Daniel Hosseinian <dhoss@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxge/cfx_pathdata.cpp b/core/fxge/cfx_pathdata.cpp index 682fc56..29cce9b 100644 --- a/core/fxge/cfx_pathdata.cpp +++ b/core/fxge/cfx_pathdata.cpp
@@ -12,96 +12,6 @@ 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) { - return a.x == b.x && b.x == c.x && (b.y - a.y) * (b.y - c.y) > 0; -} - -bool IsFoldingHorizontalLine(const CFX_PointF& a, - const CFX_PointF& b, - const CFX_PointF& c) { - return a.y == b.y && b.y == c.y && (b.x - a.x) * (b.x - c.x) > 0; -} - -bool IsFoldingDiagonalLine(const CFX_PointF& a, - const CFX_PointF& b, - const CFX_PointF& c) { - return a.x != b.x && c.x != b.x && a.y != b.y && c.y != b.y && - (a.y - b.y) * (c.x - b.x) == (c.y - b.y) * (a.x - b.x); -} - void UpdateLineEndPoints(CFX_FloatRect* rect, const CFX_PointF& start_pos, const CFX_PointF& end_pos, @@ -392,76 +302,6 @@ point.m_Point = matrix.Transform(point.m_Point); } -bool CFX_PathData::GetZeroAreaPath(const CFX_Matrix* matrix, - bool adjust, - CFX_PathData* new_path, - 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 (CheckSimpleLinePath(m_Points, matrix, adjust, new_path, thin, - set_identity)) { - 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++) { - FXPT_TYPE point_type = m_Points[i].m_Type; - if (point_type == FXPT_TYPE::MoveTo) { - start_point = i; - continue; - } - - if (point_type == FXPT_TYPE::BezierTo) { - i += 2; - continue; - } - - DCHECK(point_type == FXPT_TYPE::LineTo); - int next_index = - (i + 1 - start_point) % (m_Points.size() - start_point) + start_point; - const FX_PATHPOINT& next = m_Points[next_index]; - if (next.m_Type == FXPT_TYPE::BezierTo || next.m_Type == FXPT_TYPE::MoveTo) - continue; - - const FX_PATHPOINT& prev = m_Points[i - 1]; - const FX_PATHPOINT& cur = m_Points[i]; - if (IsFoldingVerticalLine(prev.m_Point, cur.m_Point, next.m_Point)) { - bool use_prev = fabs(cur.m_Point.y - prev.m_Point.y) < - fabs(cur.m_Point.y - next.m_Point.y); - const FX_PATHPOINT& start = use_prev ? prev : cur; - const FX_PATHPOINT& end = use_prev ? m_Points[next_index - 1] : next; - new_path->AppendPoint(start.m_Point, FXPT_TYPE::MoveTo); - new_path->AppendPoint(end.m_Point, FXPT_TYPE::LineTo); - continue; - } - - if (IsFoldingHorizontalLine(prev.m_Point, cur.m_Point, next.m_Point) || - IsFoldingDiagonalLine(prev.m_Point, cur.m_Point, next.m_Point)) { - bool use_prev = fabs(cur.m_Point.x - prev.m_Point.x) < - fabs(cur.m_Point.x - next.m_Point.x); - const FX_PATHPOINT& start = use_prev ? prev : cur; - const FX_PATHPOINT& end = use_prev ? m_Points[next_index - 1] : next; - new_path->AppendPoint(start.m_Point, FXPT_TYPE::MoveTo); - new_path->AppendPoint(end.m_Point, FXPT_TYPE::LineTo); - continue; - } - } - - size_t new_path_size = new_path->GetPoints().size(); - if (m_Points.size() > 3 && new_path_size > 0) - *thin = true; - return new_path_size != 0; -} - bool CFX_PathData::IsRect() const { if (m_Points.size() != 5 && m_Points.size() != 4) return false;
diff --git a/core/fxge/cfx_pathdata.h b/core/fxge/cfx_pathdata.h index 9af026a..860807e7 100644 --- a/core/fxge/cfx_pathdata.h +++ b/core/fxge/cfx_pathdata.h
@@ -55,11 +55,6 @@ void Transform(const CFX_Matrix& matrix); bool IsRect() const; - bool GetZeroAreaPath(const CFX_Matrix* matrix, - bool adjust, - CFX_PathData* new_path, - bool* thin, - bool* set_identity) const; Optional<CFX_FloatRect> GetRect(const CFX_Matrix* matrix) const; void Append(const CFX_PathData* src, const CFX_Matrix* matrix);
diff --git a/core/fxge/cfx_renderdevice.cpp b/core/fxge/cfx_renderdevice.cpp index 5738027..ae9c723 100644 --- a/core/fxge/cfx_renderdevice.cpp +++ b/core/fxge/cfx_renderdevice.cpp
@@ -314,6 +314,167 @@ return true; } +// Returns true if the simple path contains 3 points which draw a line from +// A->B->A and form a zero area. +bool CheckSimpleLinePath(pdfium::span<const 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(pdfium::span<const 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) { + return a.x == b.x && b.x == c.x && (b.y - a.y) * (b.y - c.y) > 0; +} + +bool IsFoldingHorizontalLine(const CFX_PointF& a, + const CFX_PointF& b, + const CFX_PointF& c) { + return a.y == b.y && b.y == c.y && (b.x - a.x) * (b.x - c.x) > 0; +} + +bool IsFoldingDiagonalLine(const CFX_PointF& a, + const CFX_PointF& b, + const CFX_PointF& c) { + return a.x != b.x && c.x != b.x && a.y != b.y && c.y != b.y && + (a.y - b.y) * (c.x - b.x) == (c.y - b.y) * (a.x - b.x); +} + +bool GetZeroAreaPath(pdfium::span<const FX_PATHPOINT> points, + const CFX_Matrix* matrix, + bool adjust, + CFX_PathData* new_path, + bool* thin, + bool* set_identity) { + *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 (points.size() < 3) + return false; + + if (CheckSimpleLinePath(points, matrix, adjust, new_path, thin, + set_identity)) { + return true; + } + + if (CheckPalindromicPath(points, new_path, thin)) + return true; + + int start_point = 0; + for (size_t i = 0; i < points.size(); i++) { + FXPT_TYPE point_type = points[i].m_Type; + if (point_type == FXPT_TYPE::MoveTo) { + start_point = i; + continue; + } + + if (point_type == FXPT_TYPE::BezierTo) { + i += 2; + continue; + } + + DCHECK(point_type == FXPT_TYPE::LineTo); + int next_index = + (i + 1 - start_point) % (points.size() - start_point) + start_point; + const FX_PATHPOINT& next = points[next_index]; + if (next.m_Type == FXPT_TYPE::BezierTo || next.m_Type == FXPT_TYPE::MoveTo) + continue; + + const FX_PATHPOINT& prev = points[i - 1]; + const FX_PATHPOINT& cur = points[i]; + if (IsFoldingVerticalLine(prev.m_Point, cur.m_Point, next.m_Point)) { + bool use_prev = fabs(cur.m_Point.y - prev.m_Point.y) < + fabs(cur.m_Point.y - next.m_Point.y); + const FX_PATHPOINT& start = use_prev ? prev : cur; + const FX_PATHPOINT& end = use_prev ? points[next_index - 1] : next; + new_path->AppendPoint(start.m_Point, FXPT_TYPE::MoveTo); + new_path->AppendPoint(end.m_Point, FXPT_TYPE::LineTo); + continue; + } + + if (IsFoldingHorizontalLine(prev.m_Point, cur.m_Point, next.m_Point) || + IsFoldingDiagonalLine(prev.m_Point, cur.m_Point, next.m_Point)) { + bool use_prev = fabs(cur.m_Point.x - prev.m_Point.x) < + fabs(cur.m_Point.x - next.m_Point.x); + const FX_PATHPOINT& start = use_prev ? prev : cur; + const FX_PATHPOINT& end = use_prev ? points[next_index - 1] : next; + new_path->AppendPoint(start.m_Point, FXPT_TYPE::MoveTo); + new_path->AppendPoint(end.m_Point, FXPT_TYPE::LineTo); + continue; + } + } + + size_t new_path_size = new_path->GetPoints().size(); + if (points.size() > 3 && new_path_size > 0) + *thin = true; + return new_path_size != 0; +} + } // namespace CFX_RenderDevice::CFX_RenderDevice() = default; @@ -535,9 +696,11 @@ CFX_PathData newPath; bool bThin = false; bool setIdentity = false; - if (pPathData->GetZeroAreaPath(pObject2Device, - !!m_pDeviceDriver->GetDriverType(), &newPath, - &bThin, &setIdentity)) { + // TODO(crbug.com/pdfium/1638): GetZeroAreaPath() should only process a sub + // path instead the whole path. + if (GetZeroAreaPath(pPathData->GetPoints(), pObject2Device, + !!m_pDeviceDriver->GetDriverType(), &newPath, &bThin, + &setIdentity)) { CFX_GraphStateData graphState; graphState.m_LineWidth = 0.0f;