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