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