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