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