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