Initial commit.
[pdfium.git] / core / src / fxge / ge / fx_ge_path.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4  \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fxcrt/fx_basic.h"\r
8 #include "../../../include/fxge/fx_ge.h"\r
9 CFX_ClipRgn::CFX_ClipRgn(int width, int height)\r
10 {\r
11     m_Type = RectI;\r
12     m_Box.left = m_Box.top = 0;\r
13     m_Box.right = width;\r
14     m_Box.bottom = height;\r
15 }\r
16 CFX_ClipRgn::CFX_ClipRgn(const FX_RECT& rect)\r
17 {\r
18     m_Type = RectI;\r
19     m_Box = rect;\r
20 }\r
21 CFX_ClipRgn::CFX_ClipRgn(const CFX_ClipRgn& src)\r
22 {\r
23     m_Type = src.m_Type;\r
24     m_Box = src.m_Box;\r
25     m_Mask = src.m_Mask;\r
26 }\r
27 CFX_ClipRgn::~CFX_ClipRgn()\r
28 {\r
29 }\r
30 void CFX_ClipRgn::Reset(const FX_RECT& rect)\r
31 {\r
32     m_Type = RectI;\r
33     m_Box = rect;\r
34     m_Mask.SetNull();\r
35 }\r
36 void CFX_ClipRgn::IntersectRect(const FX_RECT& rect)\r
37 {\r
38     if (m_Type == RectI) {\r
39         m_Box.Intersect(rect);\r
40         return;\r
41     }\r
42     if (m_Type == MaskF) {\r
43         IntersectMaskRect(rect, m_Box, m_Mask);\r
44         return;\r
45     }\r
46 }\r
47 void CFX_ClipRgn::IntersectMaskRect(FX_RECT rect, FX_RECT mask_rect, CFX_DIBitmapRef Mask)\r
48 {\r
49     const CFX_DIBitmap* mask_dib = Mask;\r
50     m_Type = MaskF;\r
51     m_Box = rect;\r
52     m_Box.Intersect(mask_rect);\r
53     if (m_Box.IsEmpty()) {\r
54         m_Type = RectI;\r
55         return;\r
56     } else if (m_Box == mask_rect) {\r
57         m_Mask = Mask;\r
58         return;\r
59     }\r
60     CFX_DIBitmap* new_dib = m_Mask.New();\r
61     if (!new_dib) {\r
62         return;\r
63     }\r
64     new_dib->Create(m_Box.Width(), m_Box.Height(), FXDIB_8bppMask);\r
65     for (int row = m_Box.top; row < m_Box.bottom; row ++) {\r
66         FX_LPBYTE dest_scan = new_dib->GetBuffer() + new_dib->GetPitch() * (row - m_Box.top);\r
67         FX_LPBYTE src_scan = mask_dib->GetBuffer() + mask_dib->GetPitch() * (row - mask_rect.top);\r
68         for (int col = m_Box.left; col < m_Box.right; col ++) {\r
69             dest_scan[col - m_Box.left] = src_scan[col - mask_rect.left];\r
70         }\r
71     }\r
72 }\r
73 void CFX_ClipRgn::IntersectMaskF(int left, int top, CFX_DIBitmapRef Mask)\r
74 {\r
75     const CFX_DIBitmap* mask_dib = Mask;\r
76     ASSERT(mask_dib->GetFormat() == FXDIB_8bppMask);\r
77     FX_RECT mask_box(left, top, left + mask_dib->GetWidth(), top + mask_dib->GetHeight());\r
78     if (m_Type == RectI) {\r
79         IntersectMaskRect(m_Box, mask_box, Mask);\r
80         return;\r
81     }\r
82     if (m_Type == MaskF) {\r
83         FX_RECT new_box = m_Box;\r
84         new_box.Intersect(mask_box);\r
85         if (new_box.IsEmpty()) {\r
86             m_Type = RectI;\r
87             m_Mask.SetNull();\r
88             m_Box = new_box;\r
89             return;\r
90         }\r
91         CFX_DIBitmapRef new_mask;\r
92         CFX_DIBitmap* new_dib = new_mask.New();\r
93         if (!new_dib) {\r
94             return;\r
95         }\r
96         new_dib->Create(new_box.Width(), new_box.Height(), FXDIB_8bppMask);\r
97         const CFX_DIBitmap* old_dib = m_Mask;\r
98         for (int row = new_box.top; row < new_box.bottom; row ++) {\r
99             FX_LPBYTE old_scan = old_dib->GetBuffer() + (row - m_Box.top) * old_dib->GetPitch();\r
100             FX_LPBYTE mask_scan = mask_dib->GetBuffer() + (row - top) * mask_dib->GetPitch();\r
101             FX_LPBYTE new_scan = new_dib->GetBuffer() + (row - new_box.top) * new_dib->GetPitch();\r
102             for (int col = new_box.left; col < new_box.right; col ++) {\r
103                 new_scan[col - new_box.left] = old_scan[col - m_Box.left] * mask_scan[col - left] / 255;\r
104             }\r
105         }\r
106         m_Box = new_box;\r
107         m_Mask = new_mask;\r
108         return;\r
109     }\r
110     ASSERT(FALSE);\r
111 }\r
112 CFX_PathData::CFX_PathData()\r
113 {\r
114     m_PointCount = m_AllocCount = 0;\r
115     m_pPoints = NULL;\r
116 }\r
117 CFX_PathData::~CFX_PathData()\r
118 {\r
119     if (m_pPoints) {\r
120         FX_Free(m_pPoints);\r
121     }\r
122 }\r
123 FX_BOOL CFX_PathData::SetPointCount(int nPoints)\r
124 {\r
125     m_PointCount = nPoints;\r
126     if (m_AllocCount < nPoints) {\r
127         if (m_pPoints) {\r
128             FX_Free(m_pPoints);\r
129             m_pPoints = NULL;\r
130         }\r
131         m_pPoints = FX_Alloc(FX_PATHPOINT, nPoints);\r
132         if (!m_pPoints) {\r
133             return FALSE;\r
134         }\r
135         m_AllocCount = nPoints;\r
136     }\r
137     return TRUE;\r
138 }\r
139 FX_BOOL CFX_PathData::AllocPointCount(int nPoints)\r
140 {\r
141     if (m_AllocCount < nPoints) {\r
142         FX_PATHPOINT* pNewBuf = FX_Alloc(FX_PATHPOINT, nPoints);\r
143         if (!pNewBuf) {\r
144             return FALSE;\r
145         }\r
146         if (m_PointCount) {\r
147             FXSYS_memcpy32(pNewBuf, m_pPoints, m_PointCount * sizeof(FX_PATHPOINT));\r
148         }\r
149         if (m_pPoints) {\r
150             FX_Free(m_pPoints);\r
151         }\r
152         m_pPoints = pNewBuf;\r
153         m_AllocCount = nPoints;\r
154     }\r
155     return TRUE;\r
156 }\r
157 CFX_PathData::CFX_PathData(const CFX_PathData& src)\r
158 {\r
159     m_pPoints = NULL;\r
160     m_PointCount = m_AllocCount = src.m_PointCount;\r
161     m_pPoints = FX_Alloc(FX_PATHPOINT, src.m_PointCount);\r
162     if (!m_pPoints) {\r
163         return;\r
164     }\r
165     FXSYS_memcpy32(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount);\r
166 }\r
167 void CFX_PathData::TrimPoints(int nPoints)\r
168 {\r
169     if (m_PointCount <= nPoints) {\r
170         return;\r
171     }\r
172     SetPointCount(nPoints);\r
173 }\r
174 FX_BOOL CFX_PathData::AddPointCount(int addPoints)\r
175 {\r
176     int new_count = m_PointCount + addPoints;\r
177     if (!AllocPointCount(new_count)) {\r
178         return FALSE;\r
179     }\r
180     m_PointCount = new_count;\r
181     return TRUE;\r
182 }\r
183 FX_BOOL CFX_PathData::Append(const CFX_PathData* pSrc, const CFX_AffineMatrix* pMatrix)\r
184 {\r
185     int old_count = m_PointCount;\r
186     if (!AddPointCount(pSrc->m_PointCount)) {\r
187         return FALSE;\r
188     }\r
189     FXSYS_memcpy32(m_pPoints + old_count, pSrc->m_pPoints, pSrc->m_PointCount * sizeof(FX_PATHPOINT));\r
190     if (pMatrix == NULL) {\r
191         return TRUE;\r
192     }\r
193     for (int i = 0; i < pSrc->m_PointCount; i ++) {\r
194         pMatrix->Transform(m_pPoints[old_count + i].m_PointX, m_pPoints[old_count + i].m_PointY);\r
195     }\r
196     return TRUE;\r
197 }\r
198 void CFX_PathData::SetPoint(int index, FX_FLOAT x, FX_FLOAT y, int flag)\r
199 {\r
200     ASSERT(index < m_PointCount);\r
201     m_pPoints[index].m_PointX = x;\r
202     m_pPoints[index].m_PointY = y;\r
203     m_pPoints[index].m_Flag = flag;\r
204 }\r
205 FX_BOOL CFX_PathData::AppendRect(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top)\r
206 {\r
207     int old_count = m_PointCount;\r
208     if (!AddPointCount(5)) {\r
209         return FALSE;\r
210     }\r
211     FX_PATHPOINT* pPoints = m_pPoints + old_count;\r
212     pPoints[0].m_PointX = pPoints[1].m_PointX = pPoints[4].m_PointX = left;\r
213     pPoints[2].m_PointX = pPoints[3].m_PointX = right;\r
214     pPoints[0].m_PointY = pPoints[3].m_PointY = pPoints[4].m_PointY = bottom;\r
215     pPoints[1].m_PointY = pPoints[2].m_PointY = top;\r
216     pPoints[0].m_Flag = FXPT_MOVETO;\r
217     pPoints[1].m_Flag = pPoints[2].m_Flag = pPoints[3].m_Flag = FXPT_LINETO;\r
218     pPoints[4].m_Flag = FXPT_LINETO | FXPT_CLOSEFIGURE;\r
219     return TRUE;\r
220 }\r
221 CFX_FloatRect CFX_PathData::GetBoundingBox() const\r
222 {\r
223     CFX_FloatRect rect;\r
224     if (m_PointCount) {\r
225         rect.InitRect(m_pPoints[0].m_PointX, m_pPoints[0].m_PointY);\r
226         for (int i = 1; i < m_PointCount; i ++) {\r
227             rect.UpdateRect(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY);\r
228         }\r
229     }\r
230     return rect;\r
231 }\r
232 static void _UpdateLineEndPoints(CFX_FloatRect& rect, FX_FLOAT start_x, FX_FLOAT start_y, FX_FLOAT end_x, FX_FLOAT end_y,\r
233                                  FX_FLOAT hw)\r
234 {\r
235     if (start_x == end_x) {\r
236         if (start_y == end_y) {\r
237             rect.UpdateRect(end_x + hw, end_y + hw);\r
238             rect.UpdateRect(end_x - hw, end_y - hw);\r
239             return;\r
240         }\r
241         FX_FLOAT point_y;\r
242         if (end_y < start_y) {\r
243             point_y = end_y - hw;\r
244         } else {\r
245             point_y = end_y + hw;\r
246         }\r
247         rect.UpdateRect(end_x + hw, point_y);\r
248         rect.UpdateRect(end_x - hw, point_y);\r
249         return;\r
250     } else if (start_y == end_y) {\r
251         FX_FLOAT point_x;\r
252         if (end_x < start_x) {\r
253             point_x = end_x - hw;\r
254         } else {\r
255             point_x = end_x + hw;\r
256         }\r
257         rect.UpdateRect(point_x, end_y + hw);\r
258         rect.UpdateRect(point_x, end_y - hw);\r
259         return;\r
260     }\r
261     FX_FLOAT dx = end_x - start_x;\r
262     FX_FLOAT dy = end_y - start_y;\r
263     FX_FLOAT ll = FXSYS_sqrt2(dx, dy);\r
264     FX_FLOAT mx = end_x + hw * dx / ll;\r
265     FX_FLOAT my = end_y + hw * dy / ll;\r
266     FX_FLOAT dx1 = hw * dy / ll;\r
267     FX_FLOAT dy1 = hw * dx / ll;\r
268     rect.UpdateRect(mx - dx1, my + dy1);\r
269     rect.UpdateRect(mx + dx1, my - dy1);\r
270 }\r
271 static void _UpdateLineJoinPoints(CFX_FloatRect& rect, FX_FLOAT start_x, FX_FLOAT start_y,\r
272                                   FX_FLOAT middle_x, FX_FLOAT middle_y, FX_FLOAT end_x, FX_FLOAT end_y,\r
273                                   FX_FLOAT half_width, FX_FLOAT miter_limit)\r
274 {\r
275     FX_FLOAT start_k = 0, start_c = 0, end_k = 0, end_c = 0, start_len = 0, start_dc = 0, end_len = 0, end_dc = 0;\r
276     FX_BOOL bStartVert = FXSYS_fabs(start_x - middle_x) < 1.0f / 20;\r
277     FX_BOOL bEndVert = FXSYS_fabs(middle_x - end_x) < 1.0f / 20;\r
278     if (bStartVert && bEndVert) {\r
279         int start_dir = middle_y > start_y ? 1 : -1;\r
280         FX_FLOAT point_y = middle_y + half_width * start_dir;\r
281         rect.UpdateRect(middle_x + half_width, point_y);\r
282         rect.UpdateRect(middle_x - half_width, point_y);\r
283         return;\r
284     }\r
285     if (!bStartVert) {\r
286         start_k = FXSYS_Div(middle_y - start_y, middle_x - start_x);\r
287         start_c = middle_y - FXSYS_Mul(start_k, middle_x);\r
288         start_len = FXSYS_sqrt2(start_x - middle_x, start_y - middle_y);\r
289         start_dc = (FX_FLOAT)FXSYS_fabs(FXSYS_MulDiv(half_width, start_len, start_x - middle_x));\r
290     }\r
291     if (!bEndVert) {\r
292         end_k = FXSYS_Div(end_y - middle_y, end_x - middle_x);\r
293         end_c = middle_y - FXSYS_Mul(end_k, middle_x);\r
294         end_len = FXSYS_sqrt2(end_x - middle_x, end_y - middle_y);\r
295         end_dc = (FX_FLOAT)FXSYS_fabs(FXSYS_MulDiv(half_width, end_len, end_x - middle_x));\r
296     }\r
297     if (bStartVert) {\r
298         FX_FLOAT outside_x = start_x;\r
299         if (end_x < start_x) {\r
300             outside_x += half_width;\r
301         } else {\r
302             outside_x -= half_width;\r
303         }\r
304         FX_FLOAT outside_y;\r
305         if (start_y < FXSYS_Mul(end_k, start_x) + end_c) {\r
306             outside_y = FXSYS_Mul(end_k, outside_x) + end_c + end_dc;\r
307         } else {\r
308             outside_y = FXSYS_Mul(end_k, outside_x) + end_c - end_dc;\r
309         }\r
310         rect.UpdateRect(outside_x, outside_y);\r
311         return;\r
312     }\r
313     if (bEndVert) {\r
314         FX_FLOAT outside_x = end_x;\r
315         if (start_x < end_x) {\r
316             outside_x += half_width;\r
317         } else {\r
318             outside_x -= half_width;\r
319         }\r
320         FX_FLOAT outside_y;\r
321         if (end_y < FXSYS_Mul(start_k, end_x) + start_c) {\r
322             outside_y = FXSYS_Mul(start_k, outside_x) + start_c + start_dc;\r
323         } else {\r
324             outside_y = FXSYS_Mul(start_k, outside_x) + start_c - start_dc;\r
325         }\r
326         rect.UpdateRect(outside_x, outside_y);\r
327         return;\r
328     }\r
329     if (FXSYS_fabs(start_k - end_k) < 1.0f / 20) {\r
330         int start_dir = middle_x > start_x ? 1 : -1;\r
331         int end_dir = end_x > middle_x ? 1 : -1;\r
332         if (start_dir == end_dir) {\r
333             _UpdateLineEndPoints(rect, middle_x, middle_y, end_x, end_y, half_width);\r
334         } else {\r
335             _UpdateLineEndPoints(rect, start_x, start_y, middle_x, middle_y, half_width);\r
336         }\r
337         return;\r
338     }\r
339     FX_FLOAT start_outside_c = start_c;\r
340     if (end_y < FXSYS_Mul(start_k, end_x) + start_c) {\r
341         start_outside_c += start_dc;\r
342     } else {\r
343         start_outside_c -= start_dc;\r
344     }\r
345     FX_FLOAT end_outside_c = end_c;\r
346     if (start_y < FXSYS_Mul(end_k, start_x) + end_c) {\r
347         end_outside_c += end_dc;\r
348     } else {\r
349         end_outside_c -= end_dc;\r
350     }\r
351     FX_FLOAT join_x = FXSYS_Div(end_outside_c - start_outside_c, start_k - end_k);\r
352     FX_FLOAT join_y = FXSYS_Mul(start_k, join_x) + start_outside_c;\r
353     rect.UpdateRect(join_x, join_y);\r
354 }\r
355 CFX_FloatRect CFX_PathData::GetBoundingBox(FX_FLOAT line_width, FX_FLOAT miter_limit) const\r
356 {\r
357     CFX_FloatRect rect(100000 * 1.0f, 100000 * 1.0f, -100000 * 1.0f, -100000 * 1.0f);\r
358     int iPoint = 0;\r
359     FX_FLOAT half_width = line_width;\r
360     int iStartPoint, iEndPoint, iMiddlePoint;\r
361     FX_BOOL bJoin;\r
362     while (iPoint < m_PointCount) {\r
363         if (m_pPoints[iPoint].m_Flag == FXPT_MOVETO) {\r
364             iStartPoint = iPoint + 1;\r
365             iEndPoint = iPoint;\r
366             bJoin = FALSE;\r
367         } else {\r
368             if (m_pPoints[iPoint].m_Flag == FXPT_BEZIERTO) {\r
369                 rect.UpdateRect(m_pPoints[iPoint].m_PointX, m_pPoints[iPoint].m_PointY);\r
370                 rect.UpdateRect(m_pPoints[iPoint + 1].m_PointX, m_pPoints[iPoint + 1].m_PointY);\r
371                 iPoint += 2;\r
372             }\r
373             if (iPoint == m_PointCount - 1 || m_pPoints[iPoint + 1].m_Flag == FXPT_MOVETO) {\r
374                 iStartPoint = iPoint - 1;\r
375                 iEndPoint = iPoint;\r
376                 bJoin = FALSE;\r
377             } else {\r
378                 iStartPoint = iPoint - 1;\r
379                 iMiddlePoint = iPoint;\r
380                 iEndPoint = iPoint + 1;\r
381                 bJoin = TRUE;\r
382             }\r
383         }\r
384         FX_FLOAT start_x = m_pPoints[iStartPoint].m_PointX;\r
385         FX_FLOAT start_y = m_pPoints[iStartPoint].m_PointY;\r
386         FX_FLOAT end_x = m_pPoints[iEndPoint].m_PointX;\r
387         FX_FLOAT end_y = m_pPoints[iEndPoint].m_PointY;\r
388         if (bJoin) {\r
389             FX_FLOAT middle_x = m_pPoints[iMiddlePoint].m_PointX;\r
390             FX_FLOAT middle_y = m_pPoints[iMiddlePoint].m_PointY;\r
391             _UpdateLineJoinPoints(rect, start_x, start_y, middle_x, middle_y, end_x, end_y, half_width, miter_limit);\r
392         } else {\r
393             _UpdateLineEndPoints(rect, start_x, start_y, end_x, end_y, half_width);\r
394         }\r
395         iPoint ++;\r
396     }\r
397     return rect;\r
398 }\r
399 void CFX_PathData::Transform(const CFX_AffineMatrix* pMatrix)\r
400 {\r
401     if (pMatrix == NULL) {\r
402         return;\r
403     }\r
404     for (int i = 0; i < m_PointCount; i ++) {\r
405         pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY);\r
406     }\r
407 }\r
408 const int g_Distant[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\r
409 FX_BOOL CFX_PathData::GetZeroAreaPath(CFX_PathData& NewPath, CFX_AffineMatrix* pMatrix, FX_BOOL&bThin, FX_BOOL bAdjust) const\r
410 {\r
411     if (m_PointCount < 3) {\r
412         return FALSE;\r
413     }\r
414     if (m_PointCount == 3 && (m_pPoints[0].m_Flag & FXPT_TYPE) == FXPT_MOVETO &&\r
415             (m_pPoints[1].m_Flag & FXPT_TYPE) == FXPT_LINETO && (m_pPoints[2].m_Flag & FXPT_TYPE) == FXPT_LINETO\r
416             && m_pPoints[0].m_PointX == m_pPoints[2].m_PointX && m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) {\r
417         NewPath.AddPointCount(2);\r
418         if (bAdjust) {\r
419             if (pMatrix) {\r
420                 FX_FLOAT x = m_pPoints[0].m_PointX, y = m_pPoints[0].m_PointY;\r
421                 pMatrix->TransformPoint(x, y);\r
422                 x = (int)x + 0.5f;\r
423                 y = (int)y + 0.5f;\r
424                 NewPath.SetPoint(0, x, y, FXPT_MOVETO);\r
425                 x = m_pPoints[1].m_PointX, y = m_pPoints[1].m_PointY;\r
426                 pMatrix->TransformPoint(x, y);\r
427                 x = (int)x + 0.5f;\r
428                 y = (int)y + 0.5f;\r
429                 NewPath.SetPoint(1, x, y, FXPT_LINETO);\r
430                 pMatrix->SetIdentity();\r
431             } else {\r
432                 FX_FLOAT x = (int)m_pPoints[0].m_PointX + 0.5f, y = (int)m_pPoints[0].m_PointY + 0.5f;\r
433                 NewPath.SetPoint(0, x, y, FXPT_MOVETO);\r
434                 x = (int)m_pPoints[1].m_PointX + 0.5f, y = (int)m_pPoints[1].m_PointY + 0.5f;\r
435                 NewPath.SetPoint(1, x, y, FXPT_LINETO);\r
436             }\r
437         } else {\r
438             NewPath.SetPoint(0, m_pPoints[0].m_PointX, m_pPoints[0].m_PointY, FXPT_MOVETO);\r
439             NewPath.SetPoint(1, m_pPoints[1].m_PointX, m_pPoints[1].m_PointY, FXPT_LINETO);\r
440         }\r
441         if (m_pPoints[0].m_PointX != m_pPoints[1].m_PointX && m_pPoints[0].m_PointY != m_pPoints[1].m_PointY) {\r
442             bThin = TRUE;\r
443         }\r
444         return TRUE;\r
445     }\r
446     if (((m_PointCount > 3) && (m_PointCount % 2))) {\r
447         int mid = m_PointCount / 2;\r
448         FX_BOOL bZeroArea = FALSE;\r
449         CFX_PathData t_path;\r
450         for (int i = 0; i < mid; i++) {\r
451             if (!(m_pPoints[mid - i - 1].m_PointX == m_pPoints[mid + i + 1].m_PointX\r
452                     && m_pPoints[mid - i - 1].m_PointY == m_pPoints[mid + i + 1].m_PointY &&\r
453                     ((m_pPoints[mid - i - 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO && (m_pPoints[mid + i + 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO))) {\r
454                 bZeroArea = TRUE;\r
455                 break;\r
456             }\r
457             int new_count = t_path.GetPointCount();\r
458             t_path.AddPointCount(2);\r
459             t_path.SetPoint(new_count, m_pPoints[mid - i].m_PointX, m_pPoints[mid - i].m_PointY, FXPT_MOVETO);\r
460             t_path.SetPoint(new_count + 1, m_pPoints[mid - i - 1].m_PointX, m_pPoints[mid - i - 1].m_PointY, FXPT_LINETO);\r
461         }\r
462         if (!bZeroArea) {\r
463             NewPath.Append(&t_path, NULL);\r
464             bThin = TRUE;\r
465             return TRUE;\r
466         }\r
467     }\r
468     int stratPoint = 0;\r
469     int next = 0, i;\r
470     for (i = 0; i < m_PointCount; i++) {\r
471         int point_type = m_pPoints[i].m_Flag & FXPT_TYPE;\r
472         if (point_type == FXPT_MOVETO) {\r
473             stratPoint = i;\r
474         } else if (point_type == FXPT_LINETO) {\r
475             next = (i + 1 - stratPoint) % (m_PointCount - stratPoint) + stratPoint;\r
476             if ((m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO && (m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_MOVETO) {\r
477                 if((m_pPoints[i - 1].m_PointX == m_pPoints[i].m_PointX && m_pPoints[i].m_PointX == m_pPoints[next].m_PointX)\r
478                         && ((m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY) * (m_pPoints[i].m_PointY - m_pPoints[next].m_PointY) > 0)) {\r
479                     int pre = i;\r
480                     if (FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY)\r
481                             < FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[next].m_PointY)) {\r
482                         pre --;\r
483                         next--;\r
484                     }\r
485                     int new_count = NewPath.GetPointCount();\r
486                     NewPath.AddPointCount(2);\r
487                     NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX, m_pPoints[pre].m_PointY, FXPT_MOVETO);\r
488                     NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX, m_pPoints[next].m_PointY, FXPT_LINETO);\r
489                 } else if((m_pPoints[i - 1].m_PointY == m_pPoints[i].m_PointY && m_pPoints[i].m_PointY == m_pPoints[next].m_PointY)\r
490                           && ((m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX) * (m_pPoints[i].m_PointX - m_pPoints[next].m_PointX) > 0)) {\r
491                     int pre = i;\r
492                     if (FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX)\r
493                             < FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[next].m_PointX)) {\r
494                         pre --;\r
495                         next--;\r
496                     }\r
497                     int new_count = NewPath.GetPointCount();\r
498                     NewPath.AddPointCount(2);\r
499                     NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX, m_pPoints[pre].m_PointY, FXPT_MOVETO);\r
500                     NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX, m_pPoints[next].m_PointY, FXPT_LINETO);\r
501                 } else if ((m_pPoints[i - 1].m_Flag & FXPT_TYPE) == FXPT_MOVETO && (m_pPoints[next].m_Flag & FXPT_TYPE) == FXPT_LINETO &&\r
502                            m_pPoints[i - 1].m_PointX == m_pPoints[next].m_PointX && m_pPoints[i - 1].m_PointY == m_pPoints[next].m_PointY\r
503                            && m_pPoints[next].m_Flag & FXPT_CLOSEFIGURE) {\r
504                     int new_count = NewPath.GetPointCount();\r
505                     NewPath.AddPointCount(2);\r
506                     NewPath.SetPoint(new_count, m_pPoints[i - 1].m_PointX, m_pPoints[i - 1].m_PointY, FXPT_MOVETO);\r
507                     NewPath.SetPoint(new_count + 1, m_pPoints[i].m_PointX, m_pPoints[i].m_PointY, FXPT_LINETO);\r
508                     bThin = TRUE;\r
509                 }\r
510             }\r
511         } else if (point_type == FXPT_BEZIERTO) {\r
512             i += 2;\r
513             continue;\r
514         }\r
515     }\r
516     if (m_PointCount > 3 && NewPath.GetPointCount()) {\r
517         bThin = TRUE;\r
518     }\r
519     if (NewPath.GetPointCount() == 0) {\r
520         return FALSE;\r
521     }\r
522     return TRUE;\r
523 }\r
524 FX_BOOL CFX_PathData::IsRect() const\r
525 {\r
526     if (m_PointCount != 5 && m_PointCount != 4) {\r
527         return FALSE;\r
528     }\r
529     if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX ||\r
530                                m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) ||\r
531             (m_pPoints[0].m_PointX == m_pPoints[2].m_PointX && m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) ||\r
532             (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX && m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) {\r
533         return FALSE;\r
534     }\r
535     if (m_pPoints[0].m_PointX != m_pPoints[3].m_PointX && m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) {\r
536         return FALSE;\r
537     }\r
538     for (int i = 1; i < 4; i ++) {\r
539         if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) {\r
540             return FALSE;\r
541         }\r
542         if (m_pPoints[i].m_PointX != m_pPoints[i - 1].m_PointX && m_pPoints[i].m_PointY != m_pPoints[i - 1].m_PointY) {\r
543             return FALSE;\r
544         }\r
545     }\r
546     return m_PointCount == 5 || (m_pPoints[3].m_Flag & FXPT_CLOSEFIGURE);\r
547 }\r
548 FX_BOOL CFX_PathData::IsRect(const CFX_AffineMatrix* pMatrix, CFX_FloatRect* pRect) const\r
549 {\r
550     if (pMatrix == NULL) {\r
551         if (!IsRect()) {\r
552             return FALSE;\r
553         }\r
554         if (pRect) {\r
555             pRect->left = m_pPoints[0].m_PointX;\r
556             pRect->right = m_pPoints[2].m_PointX;\r
557             pRect->bottom = m_pPoints[0].m_PointY;\r
558             pRect->top = m_pPoints[2].m_PointY;\r
559             pRect->Normalize();\r
560         }\r
561         return TRUE;\r
562     }\r
563     if (m_PointCount != 5 && m_PointCount != 4) {\r
564         return FALSE;\r
565     }\r
566     if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX || m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) ||\r
567             (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX && m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) {\r
568         return FALSE;\r
569     }\r
570     if (m_PointCount == 4 && m_pPoints[0].m_PointX != m_pPoints[3].m_PointX && m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) {\r
571         return FALSE;\r
572     }\r
573     FX_FLOAT x[5], y[5];\r
574     for (int i = 0; i < m_PointCount; i ++) {\r
575         pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY, x[i], y[i]);\r
576         if (i) {\r
577             if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) {\r
578                 return FALSE;\r
579             }\r
580             if (x[i] != x[i - 1] && y[i] != y[i - 1]) {\r
581                 return FALSE;\r
582             }\r
583         }\r
584     }\r
585     if (pRect) {\r
586         pRect->left = x[0];\r
587         pRect->right = x[2];\r
588         pRect->bottom = y[0];\r
589         pRect->top = y[2];\r
590         pRect->Normalize();\r
591     }\r
592     return TRUE;\r
593 }\r
594 FX_BOOL CFX_PathData::Copy(const CFX_PathData &src)\r
595 {\r
596     if (!SetPointCount(src.m_PointCount)) {\r
597         return FALSE;\r
598     }\r
599     FXSYS_memcpy32(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount);\r
600     return TRUE;\r
601 }\r
602 CFX_GraphStateData::CFX_GraphStateData()\r
603 {\r
604     m_LineCap = LineCapButt;\r
605     m_DashCount = 0;\r
606     m_DashArray = NULL;\r
607     m_DashPhase = 0;\r
608     m_LineJoin = LineJoinMiter;\r
609     m_MiterLimit = 10 * 1.0f;\r
610     m_LineWidth = 1.0f;\r
611 }\r
612 CFX_GraphStateData::CFX_GraphStateData(const CFX_GraphStateData& src)\r
613 {\r
614     m_DashArray = NULL;\r
615     Copy(src);\r
616 }\r
617 void CFX_GraphStateData::Copy(const CFX_GraphStateData& src)\r
618 {\r
619     m_LineCap = src.m_LineCap;\r
620     m_DashCount = src.m_DashCount;\r
621     if (m_DashArray) {\r
622         FX_Free(m_DashArray);\r
623     }\r
624     m_DashArray = NULL;\r
625     m_DashPhase = src.m_DashPhase;\r
626     m_LineJoin = src.m_LineJoin;\r
627     m_MiterLimit = src.m_MiterLimit;\r
628     m_LineWidth = src.m_LineWidth;\r
629     if (m_DashCount) {\r
630         m_DashArray = FX_Alloc(FX_FLOAT, m_DashCount);\r
631         if (!m_DashArray) {\r
632             return;\r
633         }\r
634         FXSYS_memcpy32(m_DashArray, src.m_DashArray, m_DashCount * sizeof(FX_FLOAT));\r
635     }\r
636 }\r
637 CFX_GraphStateData::~CFX_GraphStateData()\r
638 {\r
639     if (m_DashArray) {\r
640         FX_Free(m_DashArray);\r
641     }\r
642 }\r
643 void CFX_GraphStateData::SetDashCount(int count)\r
644 {\r
645     if (m_DashArray) {\r
646         FX_Free(m_DashArray);\r
647     }\r
648     m_DashArray = NULL;\r
649     m_DashCount = count;\r
650     if (count == 0) {\r
651         return;\r
652     }\r
653     m_DashArray = FX_Alloc(FX_FLOAT, count);\r
654 }\r