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;