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 11CFX_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} 18CFX_ClipRgn::CFX_ClipRgn(const FX_RECT& rect) 19{ 20 m_Type = RectI; 21 m_Box = rect; 22} 23CFX_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} 29CFX_ClipRgn::~CFX_ClipRgn() 30{ 31} 32void CFX_ClipRgn::Reset(const FX_RECT& rect) 33{ 34 m_Type = RectI; 35 m_Box = rect; 36 m_Mask.SetNull(); 37} 38void 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} 49void 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} 75void 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} 114CFX_PathData::CFX_PathData() 115{ 116 m_PointCount = m_AllocCount = 0; 117 m_pPoints = NULL; 118} 119CFX_PathData::~CFX_PathData() 120{ 121 if (m_pPoints) { 122 FX_Free(m_pPoints); 123 } 124} 125void 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} 137void 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} 151CFX_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} 157void CFX_PathData::TrimPoints(int nPoints) 158{ 159 if (m_PointCount <= nPoints) { 160 return; 161 } 162 SetPointCount(nPoints); 163} 164void 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} 172void 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} 183void 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} 190void 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} 203CFX_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} 214static 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} 253static 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} 337CFX_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} 381void 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} 390FX_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} 505FX_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} 529FX_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} 575void 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} 580CFX_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} 590CFX_GraphStateData::CFX_GraphStateData(const CFX_GraphStateData& src) 591{ 592 m_DashArray = NULL; 593 Copy(src); 594} 595void 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} 612CFX_GraphStateData::~CFX_GraphStateData() 613{ 614 if (m_DashArray) { 615 FX_Free(m_DashArray); 616 } 617} 618void 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