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
CFX_ClipRgn(int width,int height)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 }
CFX_ClipRgn(const FX_RECT & rect)18 CFX_ClipRgn::CFX_ClipRgn(const FX_RECT& rect)
19 {
20 m_Type = RectI;
21 m_Box = rect;
22 }
CFX_ClipRgn(const CFX_ClipRgn & src)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 }
~CFX_ClipRgn()29 CFX_ClipRgn::~CFX_ClipRgn()
30 {
31 }
Reset(const FX_RECT & rect)32 void CFX_ClipRgn::Reset(const FX_RECT& rect)
33 {
34 m_Type = RectI;
35 m_Box = rect;
36 m_Mask.SetNull();
37 }
IntersectRect(const FX_RECT & rect)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 }
IntersectMaskRect(FX_RECT rect,FX_RECT mask_rect,CFX_DIBitmapRef Mask)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 }
IntersectMaskF(int left,int top,CFX_DIBitmapRef Mask)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 }
CFX_PathData()114 CFX_PathData::CFX_PathData()
115 {
116 m_PointCount = m_AllocCount = 0;
117 m_pPoints = NULL;
118 }
~CFX_PathData()119 CFX_PathData::~CFX_PathData()
120 {
121 if (m_pPoints) {
122 FX_Free(m_pPoints);
123 }
124 }
SetPointCount(int nPoints)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 }
AllocPointCount(int nPoints)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 }
CFX_PathData(const CFX_PathData & src)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 }
TrimPoints(int nPoints)157 void CFX_PathData::TrimPoints(int nPoints)
158 {
159 if (m_PointCount <= nPoints) {
160 return;
161 }
162 SetPointCount(nPoints);
163 }
AddPointCount(int addPoints)164 void CFX_PathData::AddPointCount(int addPoints)
165 {
166 pdfium::base::CheckedNumeric<int> safe_new_count = m_PointCount;
167 safe_new_count += addPoints;
168 int new_count = safe_new_count.ValueOrDie();
169 AllocPointCount(new_count);
170 m_PointCount = new_count;
171 }
Append(const CFX_PathData * pSrc,const CFX_AffineMatrix * pMatrix)172 void CFX_PathData::Append(const CFX_PathData* pSrc, const CFX_AffineMatrix* pMatrix)
173 {
174 int old_count = m_PointCount;
175 AddPointCount(pSrc->m_PointCount);
176 FXSYS_memcpy32(m_pPoints + old_count, pSrc->m_pPoints, pSrc->m_PointCount * sizeof(FX_PATHPOINT));
177 if (pMatrix) {
178 for (int i = 0; i < pSrc->m_PointCount; i ++) {
179 pMatrix->Transform(m_pPoints[old_count + i].m_PointX, m_pPoints[old_count + i].m_PointY);
180 }
181 }
182 }
SetPoint(int index,FX_FLOAT x,FX_FLOAT y,int flag)183 void CFX_PathData::SetPoint(int index, FX_FLOAT x, FX_FLOAT y, int flag)
184 {
185 ASSERT(index < m_PointCount);
186 m_pPoints[index].m_PointX = x;
187 m_pPoints[index].m_PointY = y;
188 m_pPoints[index].m_Flag = flag;
189 }
AppendRect(FX_FLOAT left,FX_FLOAT bottom,FX_FLOAT right,FX_FLOAT top)190 void CFX_PathData::AppendRect(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top)
191 {
192 int old_count = m_PointCount;
193 AddPointCount(5);
194 FX_PATHPOINT* pPoints = m_pPoints + old_count;
195 pPoints[0].m_PointX = pPoints[1].m_PointX = pPoints[4].m_PointX = left;
196 pPoints[2].m_PointX = pPoints[3].m_PointX = right;
197 pPoints[0].m_PointY = pPoints[3].m_PointY = pPoints[4].m_PointY = bottom;
198 pPoints[1].m_PointY = pPoints[2].m_PointY = top;
199 pPoints[0].m_Flag = FXPT_MOVETO;
200 pPoints[1].m_Flag = pPoints[2].m_Flag = pPoints[3].m_Flag = FXPT_LINETO;
201 pPoints[4].m_Flag = FXPT_LINETO | FXPT_CLOSEFIGURE;
202 }
GetBoundingBox() const203 CFX_FloatRect CFX_PathData::GetBoundingBox() const
204 {
205 CFX_FloatRect rect;
206 if (m_PointCount) {
207 rect.InitRect(m_pPoints[0].m_PointX, m_pPoints[0].m_PointY);
208 for (int i = 1; i < m_PointCount; i ++) {
209 rect.UpdateRect(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY);
210 }
211 }
212 return rect;
213 }
_UpdateLineEndPoints(CFX_FloatRect & rect,FX_FLOAT start_x,FX_FLOAT start_y,FX_FLOAT end_x,FX_FLOAT end_y,FX_FLOAT hw)214 static void _UpdateLineEndPoints(CFX_FloatRect& rect, FX_FLOAT start_x, FX_FLOAT start_y, FX_FLOAT end_x, FX_FLOAT end_y,
215 FX_FLOAT hw)
216 {
217 if (start_x == end_x) {
218 if (start_y == end_y) {
219 rect.UpdateRect(end_x + hw, end_y + hw);
220 rect.UpdateRect(end_x - hw, end_y - hw);
221 return;
222 }
223 FX_FLOAT point_y;
224 if (end_y < start_y) {
225 point_y = end_y - hw;
226 } else {
227 point_y = end_y + hw;
228 }
229 rect.UpdateRect(end_x + hw, point_y);
230 rect.UpdateRect(end_x - hw, point_y);
231 return;
232 } else if (start_y == end_y) {
233 FX_FLOAT point_x;
234 if (end_x < start_x) {
235 point_x = end_x - hw;
236 } else {
237 point_x = end_x + hw;
238 }
239 rect.UpdateRect(point_x, end_y + hw);
240 rect.UpdateRect(point_x, end_y - hw);
241 return;
242 }
243 FX_FLOAT dx = end_x - start_x;
244 FX_FLOAT dy = end_y - start_y;
245 FX_FLOAT ll = FXSYS_sqrt2(dx, dy);
246 FX_FLOAT mx = end_x + hw * dx / ll;
247 FX_FLOAT my = end_y + hw * dy / ll;
248 FX_FLOAT dx1 = hw * dy / ll;
249 FX_FLOAT dy1 = hw * dx / ll;
250 rect.UpdateRect(mx - dx1, my + dy1);
251 rect.UpdateRect(mx + dx1, my - dy1);
252 }
_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)253 static void _UpdateLineJoinPoints(CFX_FloatRect& rect, FX_FLOAT start_x, FX_FLOAT start_y,
254 FX_FLOAT middle_x, FX_FLOAT middle_y, FX_FLOAT end_x, FX_FLOAT end_y,
255 FX_FLOAT half_width, FX_FLOAT miter_limit)
256 {
257 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;
258 FX_BOOL bStartVert = FXSYS_fabs(start_x - middle_x) < 1.0f / 20;
259 FX_BOOL bEndVert = FXSYS_fabs(middle_x - end_x) < 1.0f / 20;
260 if (bStartVert && bEndVert) {
261 int start_dir = middle_y > start_y ? 1 : -1;
262 FX_FLOAT point_y = middle_y + half_width * start_dir;
263 rect.UpdateRect(middle_x + half_width, point_y);
264 rect.UpdateRect(middle_x - half_width, point_y);
265 return;
266 }
267 if (!bStartVert) {
268 start_k = FXSYS_Div(middle_y - start_y, middle_x - start_x);
269 start_c = middle_y - FXSYS_Mul(start_k, middle_x);
270 start_len = FXSYS_sqrt2(start_x - middle_x, start_y - middle_y);
271 start_dc = (FX_FLOAT)FXSYS_fabs(FXSYS_MulDiv(half_width, start_len, start_x - middle_x));
272 }
273 if (!bEndVert) {
274 end_k = FXSYS_Div(end_y - middle_y, end_x - middle_x);
275 end_c = middle_y - FXSYS_Mul(end_k, middle_x);
276 end_len = FXSYS_sqrt2(end_x - middle_x, end_y - middle_y);
277 end_dc = (FX_FLOAT)FXSYS_fabs(FXSYS_MulDiv(half_width, end_len, end_x - middle_x));
278 }
279 if (bStartVert) {
280 FX_FLOAT outside_x = start_x;
281 if (end_x < start_x) {
282 outside_x += half_width;
283 } else {
284 outside_x -= half_width;
285 }
286 FX_FLOAT outside_y;
287 if (start_y < FXSYS_Mul(end_k, start_x) + end_c) {
288 outside_y = FXSYS_Mul(end_k, outside_x) + end_c + end_dc;
289 } else {
290 outside_y = FXSYS_Mul(end_k, outside_x) + end_c - end_dc;
291 }
292 rect.UpdateRect(outside_x, outside_y);
293 return;
294 }
295 if (bEndVert) {
296 FX_FLOAT outside_x = end_x;
297 if (start_x < end_x) {
298 outside_x += half_width;
299 } else {
300 outside_x -= half_width;
301 }
302 FX_FLOAT outside_y;
303 if (end_y < FXSYS_Mul(start_k, end_x) + start_c) {
304 outside_y = FXSYS_Mul(start_k, outside_x) + start_c + start_dc;
305 } else {
306 outside_y = FXSYS_Mul(start_k, outside_x) + start_c - start_dc;
307 }
308 rect.UpdateRect(outside_x, outside_y);
309 return;
310 }
311 if (FXSYS_fabs(start_k - end_k) < 1.0f / 20) {
312 int start_dir = middle_x > start_x ? 1 : -1;
313 int end_dir = end_x > middle_x ? 1 : -1;
314 if (start_dir == end_dir) {
315 _UpdateLineEndPoints(rect, middle_x, middle_y, end_x, end_y, half_width);
316 } else {
317 _UpdateLineEndPoints(rect, start_x, start_y, middle_x, middle_y, half_width);
318 }
319 return;
320 }
321 FX_FLOAT start_outside_c = start_c;
322 if (end_y < FXSYS_Mul(start_k, end_x) + start_c) {
323 start_outside_c += start_dc;
324 } else {
325 start_outside_c -= start_dc;
326 }
327 FX_FLOAT end_outside_c = end_c;
328 if (start_y < FXSYS_Mul(end_k, start_x) + end_c) {
329 end_outside_c += end_dc;
330 } else {
331 end_outside_c -= end_dc;
332 }
333 FX_FLOAT join_x = FXSYS_Div(end_outside_c - start_outside_c, start_k - end_k);
334 FX_FLOAT join_y = FXSYS_Mul(start_k, join_x) + start_outside_c;
335 rect.UpdateRect(join_x, join_y);
336 }
GetBoundingBox(FX_FLOAT line_width,FX_FLOAT miter_limit) const337 CFX_FloatRect CFX_PathData::GetBoundingBox(FX_FLOAT line_width, FX_FLOAT miter_limit) const
338 {
339 CFX_FloatRect rect(100000 * 1.0f, 100000 * 1.0f, -100000 * 1.0f, -100000 * 1.0f);
340 int iPoint = 0;
341 FX_FLOAT half_width = line_width;
342 int iStartPoint, iEndPoint, iMiddlePoint;
343 FX_BOOL bJoin;
344 while (iPoint < m_PointCount) {
345 if (m_pPoints[iPoint].m_Flag == FXPT_MOVETO) {
346 iStartPoint = iPoint + 1;
347 iEndPoint = iPoint;
348 bJoin = FALSE;
349 } else {
350 if (m_pPoints[iPoint].m_Flag == FXPT_BEZIERTO) {
351 rect.UpdateRect(m_pPoints[iPoint].m_PointX, m_pPoints[iPoint].m_PointY);
352 rect.UpdateRect(m_pPoints[iPoint + 1].m_PointX, m_pPoints[iPoint + 1].m_PointY);
353 iPoint += 2;
354 }
355 if (iPoint == m_PointCount - 1 || m_pPoints[iPoint + 1].m_Flag == FXPT_MOVETO) {
356 iStartPoint = iPoint - 1;
357 iEndPoint = iPoint;
358 bJoin = FALSE;
359 } else {
360 iStartPoint = iPoint - 1;
361 iMiddlePoint = iPoint;
362 iEndPoint = iPoint + 1;
363 bJoin = TRUE;
364 }
365 }
366 FX_FLOAT start_x = m_pPoints[iStartPoint].m_PointX;
367 FX_FLOAT start_y = m_pPoints[iStartPoint].m_PointY;
368 FX_FLOAT end_x = m_pPoints[iEndPoint].m_PointX;
369 FX_FLOAT end_y = m_pPoints[iEndPoint].m_PointY;
370 if (bJoin) {
371 FX_FLOAT middle_x = m_pPoints[iMiddlePoint].m_PointX;
372 FX_FLOAT middle_y = m_pPoints[iMiddlePoint].m_PointY;
373 _UpdateLineJoinPoints(rect, start_x, start_y, middle_x, middle_y, end_x, end_y, half_width, miter_limit);
374 } else {
375 _UpdateLineEndPoints(rect, start_x, start_y, end_x, end_y, half_width);
376 }
377 iPoint ++;
378 }
379 return rect;
380 }
Transform(const CFX_AffineMatrix * pMatrix)381 void CFX_PathData::Transform(const CFX_AffineMatrix* pMatrix)
382 {
383 if (pMatrix == NULL) {
384 return;
385 }
386 for (int i = 0; i < m_PointCount; i ++) {
387 pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY);
388 }
389 }
GetZeroAreaPath(CFX_PathData & NewPath,CFX_AffineMatrix * pMatrix,FX_BOOL & bThin,FX_BOOL bAdjust) const390 FX_BOOL CFX_PathData::GetZeroAreaPath(CFX_PathData& NewPath, CFX_AffineMatrix* pMatrix, FX_BOOL&bThin, FX_BOOL bAdjust) const
391 {
392 if (m_PointCount < 3) {
393 return FALSE;
394 }
395 if (m_PointCount == 3 && (m_pPoints[0].m_Flag & FXPT_TYPE) == FXPT_MOVETO &&
396 (m_pPoints[1].m_Flag & FXPT_TYPE) == FXPT_LINETO && (m_pPoints[2].m_Flag & FXPT_TYPE) == FXPT_LINETO
397 && m_pPoints[0].m_PointX == m_pPoints[2].m_PointX && m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) {
398 NewPath.AddPointCount(2);
399 if (bAdjust) {
400 if (pMatrix) {
401 FX_FLOAT x = m_pPoints[0].m_PointX, y = m_pPoints[0].m_PointY;
402 pMatrix->TransformPoint(x, y);
403 x = (int)x + 0.5f;
404 y = (int)y + 0.5f;
405 NewPath.SetPoint(0, x, y, FXPT_MOVETO);
406 x = m_pPoints[1].m_PointX, y = m_pPoints[1].m_PointY;
407 pMatrix->TransformPoint(x, y);
408 x = (int)x + 0.5f;
409 y = (int)y + 0.5f;
410 NewPath.SetPoint(1, x, y, FXPT_LINETO);
411 pMatrix->SetIdentity();
412 } else {
413 FX_FLOAT x = (int)m_pPoints[0].m_PointX + 0.5f, y = (int)m_pPoints[0].m_PointY + 0.5f;
414 NewPath.SetPoint(0, x, y, FXPT_MOVETO);
415 x = (int)m_pPoints[1].m_PointX + 0.5f, y = (int)m_pPoints[1].m_PointY + 0.5f;
416 NewPath.SetPoint(1, x, y, FXPT_LINETO);
417 }
418 } else {
419 NewPath.SetPoint(0, m_pPoints[0].m_PointX, m_pPoints[0].m_PointY, FXPT_MOVETO);
420 NewPath.SetPoint(1, m_pPoints[1].m_PointX, m_pPoints[1].m_PointY, FXPT_LINETO);
421 }
422 if (m_pPoints[0].m_PointX != m_pPoints[1].m_PointX && m_pPoints[0].m_PointY != m_pPoints[1].m_PointY) {
423 bThin = TRUE;
424 }
425 return TRUE;
426 }
427 if (((m_PointCount > 3) && (m_PointCount % 2))) {
428 int mid = m_PointCount / 2;
429 FX_BOOL bZeroArea = FALSE;
430 CFX_PathData t_path;
431 for (int i = 0; i < mid; i++) {
432 if (!(m_pPoints[mid - i - 1].m_PointX == m_pPoints[mid + i + 1].m_PointX
433 && m_pPoints[mid - i - 1].m_PointY == m_pPoints[mid + i + 1].m_PointY &&
434 ((m_pPoints[mid - i - 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO && (m_pPoints[mid + i + 1].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO))) {
435 bZeroArea = TRUE;
436 break;
437 }
438 int new_count = t_path.GetPointCount();
439 t_path.AddPointCount(2);
440 t_path.SetPoint(new_count, m_pPoints[mid - i].m_PointX, m_pPoints[mid - i].m_PointY, FXPT_MOVETO);
441 t_path.SetPoint(new_count + 1, m_pPoints[mid - i - 1].m_PointX, m_pPoints[mid - i - 1].m_PointY, FXPT_LINETO);
442 }
443 if (!bZeroArea) {
444 NewPath.Append(&t_path, NULL);
445 bThin = TRUE;
446 return TRUE;
447 }
448 }
449 int stratPoint = 0;
450 int next = 0, i;
451 for (i = 0; i < m_PointCount; i++) {
452 int point_type = m_pPoints[i].m_Flag & FXPT_TYPE;
453 if (point_type == FXPT_MOVETO) {
454 stratPoint = i;
455 } else if (point_type == FXPT_LINETO) {
456 next = (i + 1 - stratPoint) % (m_PointCount - stratPoint) + stratPoint;
457 if ((m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_BEZIERTO && (m_pPoints[next].m_Flag & FXPT_TYPE) != FXPT_MOVETO) {
458 if((m_pPoints[i - 1].m_PointX == m_pPoints[i].m_PointX && m_pPoints[i].m_PointX == m_pPoints[next].m_PointX)
459 && ((m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY) * (m_pPoints[i].m_PointY - m_pPoints[next].m_PointY) > 0)) {
460 int pre = i;
461 if (FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[i - 1].m_PointY)
462 < FXSYS_fabs(m_pPoints[i].m_PointY - m_pPoints[next].m_PointY)) {
463 pre --;
464 next--;
465 }
466 int new_count = NewPath.GetPointCount();
467 NewPath.AddPointCount(2);
468 NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX, m_pPoints[pre].m_PointY, FXPT_MOVETO);
469 NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX, m_pPoints[next].m_PointY, FXPT_LINETO);
470 } else if((m_pPoints[i - 1].m_PointY == m_pPoints[i].m_PointY && m_pPoints[i].m_PointY == m_pPoints[next].m_PointY)
471 && ((m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX) * (m_pPoints[i].m_PointX - m_pPoints[next].m_PointX) > 0)) {
472 int pre = i;
473 if (FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[i - 1].m_PointX)
474 < FXSYS_fabs(m_pPoints[i].m_PointX - m_pPoints[next].m_PointX)) {
475 pre --;
476 next--;
477 }
478 int new_count = NewPath.GetPointCount();
479 NewPath.AddPointCount(2);
480 NewPath.SetPoint(new_count, m_pPoints[pre].m_PointX, m_pPoints[pre].m_PointY, FXPT_MOVETO);
481 NewPath.SetPoint(new_count + 1, m_pPoints[next].m_PointX, m_pPoints[next].m_PointY, FXPT_LINETO);
482 } else if ((m_pPoints[i - 1].m_Flag & FXPT_TYPE) == FXPT_MOVETO && (m_pPoints[next].m_Flag & FXPT_TYPE) == FXPT_LINETO &&
483 m_pPoints[i - 1].m_PointX == m_pPoints[next].m_PointX && m_pPoints[i - 1].m_PointY == m_pPoints[next].m_PointY
484 && m_pPoints[next].m_Flag & FXPT_CLOSEFIGURE) {
485 int new_count = NewPath.GetPointCount();
486 NewPath.AddPointCount(2);
487 NewPath.SetPoint(new_count, m_pPoints[i - 1].m_PointX, m_pPoints[i - 1].m_PointY, FXPT_MOVETO);
488 NewPath.SetPoint(new_count + 1, m_pPoints[i].m_PointX, m_pPoints[i].m_PointY, FXPT_LINETO);
489 bThin = TRUE;
490 }
491 }
492 } else if (point_type == FXPT_BEZIERTO) {
493 i += 2;
494 continue;
495 }
496 }
497 if (m_PointCount > 3 && NewPath.GetPointCount()) {
498 bThin = TRUE;
499 }
500 if (NewPath.GetPointCount() == 0) {
501 return FALSE;
502 }
503 return TRUE;
504 }
IsRect() const505 FX_BOOL CFX_PathData::IsRect() const
506 {
507 if (m_PointCount != 5 && m_PointCount != 4) {
508 return FALSE;
509 }
510 if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX ||
511 m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) ||
512 (m_pPoints[0].m_PointX == m_pPoints[2].m_PointX && m_pPoints[0].m_PointY == m_pPoints[2].m_PointY) ||
513 (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX && m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) {
514 return FALSE;
515 }
516 if (m_pPoints[0].m_PointX != m_pPoints[3].m_PointX && m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) {
517 return FALSE;
518 }
519 for (int i = 1; i < 4; i ++) {
520 if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) {
521 return FALSE;
522 }
523 if (m_pPoints[i].m_PointX != m_pPoints[i - 1].m_PointX && m_pPoints[i].m_PointY != m_pPoints[i - 1].m_PointY) {
524 return FALSE;
525 }
526 }
527 return m_PointCount == 5 || (m_pPoints[3].m_Flag & FXPT_CLOSEFIGURE);
528 }
IsRect(const CFX_AffineMatrix * pMatrix,CFX_FloatRect * pRect) const529 FX_BOOL CFX_PathData::IsRect(const CFX_AffineMatrix* pMatrix, CFX_FloatRect* pRect) const
530 {
531 if (pMatrix == NULL) {
532 if (!IsRect()) {
533 return FALSE;
534 }
535 if (pRect) {
536 pRect->left = m_pPoints[0].m_PointX;
537 pRect->right = m_pPoints[2].m_PointX;
538 pRect->bottom = m_pPoints[0].m_PointY;
539 pRect->top = m_pPoints[2].m_PointY;
540 pRect->Normalize();
541 }
542 return TRUE;
543 }
544 if (m_PointCount != 5 && m_PointCount != 4) {
545 return FALSE;
546 }
547 if ((m_PointCount == 5 && (m_pPoints[0].m_PointX != m_pPoints[4].m_PointX || m_pPoints[0].m_PointY != m_pPoints[4].m_PointY)) ||
548 (m_pPoints[1].m_PointX == m_pPoints[3].m_PointX && m_pPoints[1].m_PointY == m_pPoints[3].m_PointY)) {
549 return FALSE;
550 }
551 if (m_PointCount == 4 && m_pPoints[0].m_PointX != m_pPoints[3].m_PointX && m_pPoints[0].m_PointY != m_pPoints[3].m_PointY) {
552 return FALSE;
553 }
554 FX_FLOAT x[5], y[5];
555 for (int i = 0; i < m_PointCount; i ++) {
556 pMatrix->Transform(m_pPoints[i].m_PointX, m_pPoints[i].m_PointY, x[i], y[i]);
557 if (i) {
558 if ((m_pPoints[i].m_Flag & FXPT_TYPE) != FXPT_LINETO) {
559 return FALSE;
560 }
561 if (x[i] != x[i - 1] && y[i] != y[i - 1]) {
562 return FALSE;
563 }
564 }
565 }
566 if (pRect) {
567 pRect->left = x[0];
568 pRect->right = x[2];
569 pRect->bottom = y[0];
570 pRect->top = y[2];
571 pRect->Normalize();
572 }
573 return TRUE;
574 }
Copy(const CFX_PathData & src)575 void CFX_PathData::Copy(const CFX_PathData &src)
576 {
577 SetPointCount(src.m_PointCount);
578 FXSYS_memcpy32(m_pPoints, src.m_pPoints, sizeof(FX_PATHPOINT) * m_PointCount);
579 }
CFX_GraphStateData()580 CFX_GraphStateData::CFX_GraphStateData()
581 {
582 m_LineCap = LineCapButt;
583 m_DashCount = 0;
584 m_DashArray = NULL;
585 m_DashPhase = 0;
586 m_LineJoin = LineJoinMiter;
587 m_MiterLimit = 10 * 1.0f;
588 m_LineWidth = 1.0f;
589 }
CFX_GraphStateData(const CFX_GraphStateData & src)590 CFX_GraphStateData::CFX_GraphStateData(const CFX_GraphStateData& src)
591 {
592 m_DashArray = NULL;
593 Copy(src);
594 }
Copy(const CFX_GraphStateData & src)595 void CFX_GraphStateData::Copy(const CFX_GraphStateData& src)
596 {
597 m_LineCap = src.m_LineCap;
598 m_DashCount = src.m_DashCount;
599 if (m_DashArray) {
600 FX_Free(m_DashArray);
601 }
602 m_DashArray = NULL;
603 m_DashPhase = src.m_DashPhase;
604 m_LineJoin = src.m_LineJoin;
605 m_MiterLimit = src.m_MiterLimit;
606 m_LineWidth = src.m_LineWidth;
607 if (m_DashCount) {
608 m_DashArray = FX_Alloc(FX_FLOAT, m_DashCount);
609 FXSYS_memcpy32(m_DashArray, src.m_DashArray, m_DashCount * sizeof(FX_FLOAT));
610 }
611 }
~CFX_GraphStateData()612 CFX_GraphStateData::~CFX_GraphStateData()
613 {
614 if (m_DashArray) {
615 FX_Free(m_DashArray);
616 }
617 }
SetDashCount(int count)618 void CFX_GraphStateData::SetDashCount(int count)
619 {
620 if (m_DashArray) {
621 FX_Free(m_DashArray);
622 }
623 m_DashArray = NULL;
624 m_DashCount = count;
625 if (count == 0) {
626 return;
627 }
628 m_DashArray = FX_Alloc(FX_FLOAT, count);
629 }
630