OLD | NEW |
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "core/fxcrt/include/fx_system.h" | 7 #include "core/fxcrt/include/fx_system.h" |
8 #include "core/fxge/include/fx_ge.h" | 8 #include "core/fxge/include/fx_ge.h" |
9 #include "third_party/base/numerics/safe_math.h" | |
10 | |
11 CFX_ClipRgn::CFX_ClipRgn(int width, int height) | |
12 : m_Type(RectI), m_Box(0, 0, width, height) {} | |
13 | |
14 CFX_ClipRgn::CFX_ClipRgn(const FX_RECT& rect) : m_Type(RectI), m_Box(rect) {} | |
15 | |
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 | |
22 CFX_ClipRgn::~CFX_ClipRgn() {} | |
23 | |
24 void CFX_ClipRgn::Reset(const FX_RECT& rect) { | |
25 m_Type = RectI; | |
26 m_Box = rect; | |
27 m_Mask.SetNull(); | |
28 } | |
29 | |
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 | |
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 | |
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 | |
116 CFX_PathData::CFX_PathData() | |
117 : m_PointCount(0), m_pPoints(nullptr), m_AllocCount(0) {} | |
118 | |
119 CFX_PathData::~CFX_PathData() { | |
120 FX_Free(m_pPoints); | |
121 } | |
122 | |
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 | |
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 | |
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 | |
150 void CFX_PathData::TrimPoints(int nPoints) { | |
151 if (m_PointCount <= nPoints) { | |
152 return; | |
153 } | |
154 SetPointCount(nPoints); | |
155 } | |
156 | |
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 | |
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 | |
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 | |
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 | |
201 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 | |
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 | |
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 | |
349 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 | |
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 | |
409 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 | |
554 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 | |
582 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 | |
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 | 9 |
638 CFX_GraphStateData::CFX_GraphStateData() | 10 CFX_GraphStateData::CFX_GraphStateData() |
639 : m_LineCap(LineCapButt), | 11 : m_LineCap(LineCapButt), |
640 m_DashCount(0), | 12 m_DashCount(0), |
641 m_DashArray(nullptr), | 13 m_DashArray(nullptr), |
642 m_DashPhase(0), | 14 m_DashPhase(0), |
643 m_LineJoin(LineJoinMiter), | 15 m_LineJoin(LineJoinMiter), |
644 m_MiterLimit(10 * 1.0f), | 16 m_MiterLimit(10 * 1.0f), |
645 m_LineWidth(1.0f) {} | 17 m_LineWidth(1.0f) {} |
646 | 18 |
(...skipping 23 matching lines...) Expand all Loading... |
670 | 42 |
671 void CFX_GraphStateData::SetDashCount(int count) { | 43 void CFX_GraphStateData::SetDashCount(int count) { |
672 FX_Free(m_DashArray); | 44 FX_Free(m_DashArray); |
673 m_DashArray = nullptr; | 45 m_DashArray = nullptr; |
674 m_DashCount = count; | 46 m_DashCount = count; |
675 if (count == 0) { | 47 if (count == 0) { |
676 return; | 48 return; |
677 } | 49 } |
678 m_DashArray = FX_Alloc(FX_FLOAT, count); | 50 m_DashArray = FX_Alloc(FX_FLOAT, count); |
679 } | 51 } |
OLD | NEW |