Home | History | Annotate | Download | only in fpdf_page
      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/fpdfapi/fpdf_page.h"
      8 #include "../../../include/fpdfapi/fpdf_module.h"
      9 #include "pageint.h"
     10 void CPDF_PageObject::Release()
     11 {
     12     delete this;
     13 }
     14 CPDF_PageObject* CPDF_PageObject::Create(int type)
     15 {
     16     switch (type) {
     17         case PDFPAGE_TEXT:
     18             return FX_NEW CPDF_TextObject;
     19         case PDFPAGE_IMAGE:
     20             return FX_NEW CPDF_ImageObject;
     21         case PDFPAGE_PATH:
     22             return FX_NEW CPDF_PathObject;
     23         case PDFPAGE_SHADING:
     24             return FX_NEW CPDF_ShadingObject;
     25         case PDFPAGE_FORM:
     26             return FX_NEW CPDF_FormObject;
     27     }
     28     return NULL;
     29 }
     30 CPDF_PageObject* CPDF_PageObject::Clone() const
     31 {
     32     CPDF_PageObject* pObj = Create(m_Type);
     33     pObj->Copy(this);
     34     return pObj;
     35 }
     36 void CPDF_PageObject::Copy(const CPDF_PageObject* pSrc)
     37 {
     38     if (m_Type != pSrc->m_Type) {
     39         return;
     40     }
     41     CopyData(pSrc);
     42     CopyStates(*pSrc);
     43     m_Left = pSrc->m_Left;
     44     m_Right = pSrc->m_Right;
     45     m_Top = pSrc->m_Top;
     46     m_Bottom = pSrc->m_Bottom;
     47 }
     48 void CPDF_PageObject::AppendClipPath(CPDF_Path path, int type, FX_BOOL bAutoMerge)
     49 {
     50     m_ClipPath.AppendPath(path, type, bAutoMerge);
     51 }
     52 void CPDF_PageObject::CopyClipPath(CPDF_PageObject* pObj)
     53 {
     54     m_ClipPath = pObj->m_ClipPath;
     55 }
     56 void CPDF_PageObject::RemoveClipPath()
     57 {
     58     m_ClipPath.SetNull();
     59 }
     60 void CPDF_PageObject::RecalcBBox()
     61 {
     62     switch (m_Type) {
     63         case PDFPAGE_TEXT:
     64             ((CPDF_TextObject*)this)->RecalcPositionData();
     65             break;
     66         case PDFPAGE_PATH:
     67             ((CPDF_PathObject*)this)->CalcBoundingBox();
     68             break;
     69         case PDFPAGE_SHADING:
     70             ((CPDF_ShadingObject*)this)->CalcBoundingBox();
     71             break;
     72     }
     73 }
     74 void CPDF_PageObject::TransformClipPath(CFX_AffineMatrix& matrix)
     75 {
     76     if (m_ClipPath.IsNull()) {
     77         return;
     78     }
     79     m_ClipPath.GetModify();
     80     m_ClipPath.Transform(matrix);
     81 }
     82 void CPDF_PageObject::TransformGeneralState(CFX_AffineMatrix& matrix)
     83 {
     84     if(m_GeneralState.IsNull()) {
     85         return;
     86     }
     87     CPDF_GeneralStateData* pGS = m_GeneralState.GetModify();
     88     pGS->m_Matrix.Concat(matrix);
     89 }
     90 FX_RECT CPDF_PageObject::GetBBox(const CFX_AffineMatrix* pMatrix) const
     91 {
     92     CFX_FloatRect rect(m_Left, m_Bottom, m_Right, m_Top);
     93     if (pMatrix) {
     94         pMatrix->TransformRect(rect);
     95     }
     96     return rect.GetOutterRect();
     97 }
     98 CPDF_TextObject::CPDF_TextObject()
     99 {
    100     m_Type = PDFPAGE_TEXT;
    101     m_pCharCodes = NULL;
    102     m_pCharPos = NULL;
    103     m_nChars = 0;
    104     m_PosX = m_PosY = 0;
    105 }
    106 CPDF_TextObject::~CPDF_TextObject()
    107 {
    108     if (m_nChars > 1 && m_pCharCodes) {
    109         FX_Free(m_pCharCodes);
    110     }
    111     if (m_pCharPos) {
    112         FX_Free(m_pCharPos);
    113     }
    114 }
    115 void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const
    116 {
    117     pInfo->m_CharCode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[index];
    118     pInfo->m_OriginX = index ? m_pCharPos[index - 1] : 0;
    119     pInfo->m_OriginY = 0;
    120     if (pInfo->m_CharCode == -1) {
    121         return;
    122     }
    123     CPDF_Font* pFont = m_TextState.GetFont();
    124     if (pFont->GetFontType() != PDFFONT_CIDFONT) {
    125         return;
    126     }
    127     if (!((CPDF_CIDFont*)pFont)->IsVertWriting()) {
    128         return;
    129     }
    130     FX_WORD CID = ((CPDF_CIDFont*)pFont)->CIDFromCharCode(pInfo->m_CharCode);
    131     pInfo->m_OriginY = pInfo->m_OriginX;
    132     pInfo->m_OriginX = 0;
    133     short vx, vy;
    134     ((CPDF_CIDFont*)pFont)->GetVertOrigin(CID, vx, vy);
    135     FX_FLOAT fontsize = m_TextState.GetFontSize();
    136     pInfo->m_OriginX -= fontsize * vx / 1000;
    137     pInfo->m_OriginY -= fontsize * vy / 1000;
    138 }
    139 int CPDF_TextObject::CountChars() const
    140 {
    141     if (m_nChars == 1) {
    142         return 1;
    143     }
    144     int count = 0;
    145     for (int i = 0; i < m_nChars; i ++)
    146         if (m_pCharCodes[i] != (FX_DWORD) - 1) {
    147             count ++;
    148         }
    149     return count;
    150 }
    151 void CPDF_TextObject::GetCharInfo(int index, FX_DWORD& charcode, FX_FLOAT& kerning) const
    152 {
    153     if (m_nChars == 1) {
    154         charcode = (FX_DWORD)(FX_UINTPTR)m_pCharCodes;
    155         kerning = 0;
    156         return;
    157     }
    158     int count = 0;
    159     for (int i = 0; i < m_nChars; i ++) {
    160         if (m_pCharCodes[i] != (FX_DWORD) - 1) {
    161             if (count == index) {
    162                 charcode = m_pCharCodes[i];
    163                 if (i == m_nChars - 1 || m_pCharCodes[i + 1] != (FX_DWORD) - 1) {
    164                     kerning = 0;
    165                 } else {
    166                     kerning = m_pCharPos[i];
    167                 }
    168                 return;
    169             }
    170             count ++;
    171         }
    172     }
    173 }
    174 void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const
    175 {
    176     if (m_nChars == 1) {
    177         GetItemInfo(0, pInfo);
    178         return;
    179     }
    180     int count = 0;
    181     for (int i = 0; i < m_nChars; i ++) {
    182         FX_DWORD charcode = m_pCharCodes[i];
    183         if (charcode == (FX_DWORD) - 1) {
    184             continue;
    185         }
    186         if (count == index) {
    187             GetItemInfo(i, pInfo);
    188             break;
    189         }
    190         count ++;
    191     }
    192 }
    193 void CPDF_TextObject::CopyData(const CPDF_PageObject* pSrc)
    194 {
    195     const CPDF_TextObject* pSrcObj = (const CPDF_TextObject*)pSrc;
    196     if (m_nChars > 1 && m_pCharCodes) {
    197         FX_Free(m_pCharCodes);
    198         m_pCharCodes = NULL;
    199     }
    200     if (m_pCharPos) {
    201         FX_Free(m_pCharPos);
    202         m_pCharPos = NULL;
    203     }
    204     m_nChars = pSrcObj->m_nChars;
    205     if (m_nChars > 1) {
    206         m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
    207         m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
    208         int i;
    209         for (i = 0; i < m_nChars; i ++) {
    210             m_pCharCodes[i] = pSrcObj->m_pCharCodes[i];
    211         }
    212         for (i = 0; i < m_nChars - 1; i ++) {
    213             m_pCharPos[i] = pSrcObj->m_pCharPos[i];
    214         }
    215     } else {
    216         m_pCharCodes = pSrcObj->m_pCharCodes;
    217     }
    218     m_PosX = pSrcObj->m_PosX;
    219     m_PosY = pSrcObj->m_PosY;
    220 }
    221 void CPDF_TextObject::GetTextMatrix(CFX_AffineMatrix* pMatrix) const
    222 {
    223     FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
    224     pMatrix->Set(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3], m_PosX, m_PosY);
    225 }
    226 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nsegs)
    227 {
    228     if (m_nChars > 1 && m_pCharCodes) {
    229         FX_Free(m_pCharCodes);
    230         m_pCharCodes = NULL;
    231     }
    232     if (m_pCharPos) {
    233         FX_Free(m_pCharPos);
    234         m_pCharPos = NULL;
    235     }
    236     CPDF_Font* pFont = m_TextState.GetFont();
    237     m_nChars = 0;
    238     for (int i = 0; i < nsegs; i ++) {
    239         m_nChars += pFont->CountChar(pStrs[i], pStrs[i].GetLength());
    240     }
    241     m_nChars += nsegs - 1;
    242     if (m_nChars > 1) {
    243         m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
    244         m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
    245         int index = 0;
    246         for (int i = 0; i < nsegs; i ++) {
    247             FX_LPCSTR segment = pStrs[i];
    248             int offset = 0, len = pStrs[i].GetLength();
    249             while (offset < len) {
    250                 m_pCharCodes[index++] = pFont->GetNextChar(segment, offset);
    251             }
    252             if (i != nsegs - 1) {
    253                 m_pCharPos[index - 1] = pKerning[i];
    254                 m_pCharCodes[index ++] = (FX_DWORD) - 1;
    255             }
    256         }
    257     } else {
    258         int offset = 0;
    259         m_pCharCodes = (FX_DWORD*)(FX_UINTPTR)pFont->GetNextChar(pStrs[0], offset);
    260     }
    261 }
    262 void CPDF_TextObject::SetText(const CFX_ByteString& str)
    263 {
    264     SetSegments(&str, NULL, 1);
    265     RecalcPositionData();
    266 }
    267 void CPDF_TextObject::SetEmpty()
    268 {
    269     if (m_nChars > 1 && m_pCharCodes) {
    270         FX_Free(m_pCharCodes);
    271     }
    272     if (m_nChars > 1 && m_pCharPos) {
    273         FX_Free(m_pCharPos);
    274     }
    275     m_nChars = 0;
    276     m_pCharCodes = NULL;
    277     m_pCharPos = NULL;
    278     m_Left = m_Right = m_PosX;
    279     m_Top = m_Bottom = m_PosY;
    280 }
    281 void CPDF_TextObject::SetText(CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nSegs)
    282 {
    283     SetSegments(pStrs, pKerning, nSegs);
    284     RecalcPositionData();
    285 }
    286 void CPDF_TextObject::SetText(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pKernings)
    287 {
    288     if (m_nChars > 1 && m_pCharCodes) {
    289         FX_Free(m_pCharCodes);
    290         m_pCharCodes = NULL;
    291     }
    292     if (m_pCharPos) {
    293         FX_Free(m_pCharPos);
    294         m_pCharPos = NULL;
    295     }
    296     int nKernings = 0;
    297     int i;
    298     for (i = 0; i < nChars - 1; i ++)
    299         if (pKernings[i] != 0) {
    300             nKernings ++;
    301         }
    302     m_nChars = nChars + nKernings;
    303     if (m_nChars > 1) {
    304         m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
    305         m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
    306         int index = 0;
    307         for (int i = 0; i < nChars; i ++) {
    308             m_pCharCodes[index++] = pCharCodes[i];
    309             if (pKernings[i] != 0 && i != nChars - 1) {
    310                 m_pCharCodes[index] = (FX_DWORD) - 1;
    311                 m_pCharPos[index - 1] = pKernings[i];
    312                 index ++;
    313             }
    314         }
    315     } else {
    316         int offset = 0;
    317         m_pCharCodes = (FX_DWORD*)(FX_UINTPTR)pCharCodes[0];
    318     }
    319     RecalcPositionData();
    320 }
    321 FX_FLOAT CPDF_TextObject::GetCharWidth(FX_DWORD charcode) const
    322 {
    323     FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
    324     CPDF_Font* pFont = m_TextState.GetFont();
    325     FX_BOOL bVertWriting = FALSE;
    326     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
    327     if (pCIDFont) {
    328         bVertWriting = pCIDFont->IsVertWriting();
    329     }
    330     if (!bVertWriting) {
    331         return pFont->GetCharWidthF(charcode, 0) * fontsize;
    332     } else {
    333         FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
    334         return pCIDFont->GetVertWidth(CID) * fontsize;
    335     }
    336 }
    337 FX_FLOAT CPDF_TextObject::GetSpaceCharWidth() const
    338 {
    339     CPDF_Font* pFont = m_TextState.GetFont();
    340     FX_DWORD charCode = m_TextState.GetFont()->CharCodeFromUnicode(32);
    341     if (charCode != (FX_DWORD) - 1) {
    342         return GetCharWidth(charCode);
    343     }
    344     FX_FLOAT fontSize = m_TextState.GetFontSize() / 4000.0f;
    345     FX_BOOL bVertWriting = FALSE;
    346     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
    347     if (pCIDFont) {
    348         bVertWriting = pCIDFont->IsVertWriting();
    349     }
    350     FX_RECT fontRect;
    351     pFont->GetFontBBox(fontRect);
    352     fontSize *= bVertWriting ? (FX_FLOAT)fontRect.Height() : (FX_FLOAT)fontRect.Width();
    353     return fontSize;
    354 }
    355 void CPDF_TextObject::GetCharRect(int index, CFX_FloatRect& rect) const
    356 {
    357     FX_FLOAT curpos = 0;
    358     CPDF_Font* pFont = m_TextState.GetFont();
    359     FX_BOOL bVertWriting = FALSE;
    360     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
    361     if (pCIDFont) {
    362         bVertWriting = pCIDFont->IsVertWriting();
    363     }
    364     FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
    365     int count = 0;
    366     for (int i = 0; i < m_nChars; i ++) {
    367         FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[i];
    368         if (charcode == (FX_DWORD) - 1) {
    369             continue;
    370         }
    371         if( count != index) {
    372             count++;
    373             continue;
    374         }
    375         FX_FLOAT curpos = i > 0 ? m_pCharPos[i - 1] : 0;
    376         FX_RECT char_rect;
    377         pFont->GetCharBBox(charcode, char_rect, 0);
    378         if (!bVertWriting) {
    379             rect.left = curpos + char_rect.left * fontsize;
    380             rect.right = curpos + char_rect.right * fontsize;
    381             rect.top = char_rect.top * fontsize;
    382             rect.bottom = char_rect.bottom * fontsize;
    383         } else {
    384             FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
    385             short vx, vy;
    386             pCIDFont->GetVertOrigin(CID, vx, vy);
    387             char_rect.left -= vx;
    388             char_rect.right -= vx;
    389             char_rect.top -= vy;
    390             char_rect.bottom -= vy;
    391             rect.left = char_rect.left * fontsize;
    392             rect.right = char_rect.right * fontsize;
    393             rect.top = curpos + char_rect.top * fontsize;
    394             rect.bottom = curpos + char_rect.bottom * fontsize;
    395         }
    396         return;
    397     }
    398 }
    399 void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX, FX_FLOAT* pTextAdvanceY, FX_FLOAT horz_scale, int level)
    400 {
    401     FX_FLOAT curpos = 0;
    402     FX_FLOAT min_x = 10000 * 1.0f, max_x = -10000 * 1.0f, min_y = 10000 * 1.0f, max_y = -10000 * 1.0f;
    403     CPDF_Font* pFont = m_TextState.GetFont();
    404     FX_BOOL bVertWriting = FALSE;
    405     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
    406     if (pCIDFont) {
    407         bVertWriting = pCIDFont->IsVertWriting();
    408     }
    409     FX_FLOAT fontsize = m_TextState.GetFontSize();
    410     for (int i = 0; i < m_nChars; i ++) {
    411         FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[i];
    412         if (charcode == (FX_DWORD) - 1) {
    413             curpos -= FXSYS_Mul(m_pCharPos[i - 1], fontsize) / 1000;
    414             continue;
    415         }
    416         if (i) {
    417             m_pCharPos[i - 1] = curpos;
    418         }
    419         FX_RECT char_rect;
    420         pFont->GetCharBBox(charcode, char_rect, level);
    421         FX_FLOAT charwidth;
    422         if (!bVertWriting) {
    423             if (min_y > char_rect.top) {
    424                 min_y = (FX_FLOAT)char_rect.top;
    425             }
    426             if (max_y < char_rect.top) {
    427                 max_y = (FX_FLOAT)char_rect.top;
    428             }
    429             if (min_y > char_rect.bottom) {
    430                 min_y = (FX_FLOAT)char_rect.bottom;
    431             }
    432             if (max_y < char_rect.bottom) {
    433                 max_y = (FX_FLOAT)char_rect.bottom;
    434             }
    435             FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;
    436             FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;
    437             if (min_x > char_left) {
    438                 min_x = char_left;
    439             }
    440             if (max_x < char_left) {
    441                 max_x = char_left;
    442             }
    443             if (min_x > char_right) {
    444                 min_x = char_right;
    445             }
    446             if (max_x < char_right) {
    447                 max_x = char_right;
    448             }
    449             charwidth = pFont->GetCharWidthF(charcode, level) * fontsize / 1000;
    450         } else {
    451             FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
    452             short vx, vy;
    453             pCIDFont->GetVertOrigin(CID, vx, vy);
    454             char_rect.left -= vx;
    455             char_rect.right -= vx;
    456             char_rect.top -= vy;
    457             char_rect.bottom -= vy;
    458             if (min_x > char_rect.left) {
    459                 min_x = (FX_FLOAT)char_rect.left;
    460             }
    461             if (max_x < char_rect.left) {
    462                 max_x = (FX_FLOAT)char_rect.left;
    463             }
    464             if (min_x > char_rect.right) {
    465                 min_x = (FX_FLOAT)char_rect.right;
    466             }
    467             if (max_x < char_rect.right) {
    468                 max_x = (FX_FLOAT)char_rect.right;
    469             }
    470             FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;
    471             FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;
    472             if (min_y > char_top) {
    473                 min_y = char_top;
    474             }
    475             if (max_y < char_top) {
    476                 max_y = char_top;
    477             }
    478             if (min_y > char_bottom) {
    479                 min_y = char_bottom;
    480             }
    481             if (max_y < char_bottom) {
    482                 max_y = char_bottom;
    483             }
    484             charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
    485         }
    486         curpos += charwidth;
    487         if (charcode == ' ' && (pCIDFont == NULL || pCIDFont->GetCharSize(32) == 1)) {
    488             curpos += m_TextState.GetObject()->m_WordSpace;
    489         }
    490         curpos += m_TextState.GetObject()->m_CharSpace;
    491     }
    492     if (bVertWriting) {
    493         if (pTextAdvanceX) {
    494             *pTextAdvanceX = 0;
    495         }
    496         if (pTextAdvanceY) {
    497             *pTextAdvanceY = curpos;
    498         }
    499         min_x = min_x * fontsize / 1000;
    500         max_x = max_x * fontsize / 1000;
    501     } else {
    502         if (pTextAdvanceX) {
    503             *pTextAdvanceX = FXSYS_Mul(curpos, horz_scale);
    504         }
    505         if (pTextAdvanceY) {
    506             *pTextAdvanceY = 0;
    507         }
    508         min_y = min_y * fontsize / 1000;
    509         max_y = max_y * fontsize / 1000;
    510     }
    511     CFX_AffineMatrix matrix;
    512     GetTextMatrix(&matrix);
    513     m_Left = min_x;
    514     m_Right = max_x;
    515     m_Bottom = min_y;
    516     m_Top = max_y;
    517     matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
    518     int textmode = m_TextState.GetObject()->m_TextMode;
    519     if (textmode == 1 || textmode == 2 || textmode == 5 || textmode == 6) {
    520         FX_FLOAT half_width = m_GraphState.GetObject()->m_LineWidth / 2;
    521         m_Left -= half_width;
    522         m_Right += half_width;
    523         m_Top += half_width;
    524         m_Bottom -= half_width;
    525     }
    526 }
    527 void CPDF_TextObject::CalcCharPos(FX_FLOAT* pPosArray) const
    528 {
    529     FX_FLOAT curpos = 0;
    530     int count = 0;
    531     CPDF_Font* pFont = m_TextState.GetFont();
    532     FX_BOOL bVertWriting = FALSE;
    533     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
    534     if (pCIDFont) {
    535         bVertWriting = pCIDFont->IsVertWriting();
    536     }
    537     FX_FLOAT fontsize = m_TextState.GetFontSize();
    538     int index = 0;
    539     for (int i = 0; i < m_nChars; i ++) {
    540         FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[i];
    541         if (charcode == (FX_DWORD) - 1) {
    542             continue;
    543         }
    544         pPosArray[index++] = i ? m_pCharPos[i - 1] : 0;
    545         FX_FLOAT charwidth;
    546         if (bVertWriting) {
    547             FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
    548             charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
    549         } else {
    550             charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000;
    551         }
    552         pPosArray[index] = pPosArray[index - 1] + charwidth;
    553         index++;
    554     }
    555 }
    556 void CPDF_TextObject::Transform(const CFX_AffineMatrix& matrix)
    557 {
    558     m_TextState.GetModify();
    559     CFX_AffineMatrix text_matrix;
    560     GetTextMatrix(&text_matrix);
    561     text_matrix.Concat(matrix);
    562     FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
    563     pTextMatrix[0] = text_matrix.GetA();
    564     pTextMatrix[1] = text_matrix.GetC();
    565     pTextMatrix[2] = text_matrix.GetB();
    566     pTextMatrix[3] = text_matrix.GetD();
    567     m_PosX = text_matrix.GetE();
    568     m_PosY = text_matrix.GetF();
    569     CalcPositionData(NULL, NULL, 0);
    570 }
    571 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y)
    572 {
    573     FX_FLOAT dx = x - m_PosX;
    574     FX_FLOAT dy = y - m_PosY;
    575     m_PosX = x;
    576     m_PosY = y;
    577     m_Left += dx;
    578     m_Right += dx;
    579     m_Top += dy;
    580     m_Bottom += dy;
    581 }
    582 void CPDF_TextObject::SetData(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos, FX_FLOAT x, FX_FLOAT y)
    583 {
    584     ASSERT(m_nChars == 0);
    585     m_nChars = nChars;
    586     m_PosX = x;
    587     m_PosY = y;
    588     if (nChars == 0) {
    589         return;
    590     }
    591     if (nChars == 1) {
    592         m_pCharCodes = (FX_DWORD*)(FX_UINTPTR) * pCharCodes;
    593     } else {
    594         m_pCharCodes = FX_Alloc(FX_DWORD, nChars);
    595         FXSYS_memcpy32(m_pCharCodes, pCharCodes, sizeof(FX_DWORD)*nChars);
    596         m_pCharPos = FX_Alloc(FX_FLOAT, nChars - 1);
    597         FXSYS_memcpy32(m_pCharPos, pCharPos, sizeof(FX_FLOAT) * (nChars - 1));
    598     }
    599     RecalcPositionData();
    600 }
    601 void CPDF_TextObject::SetTextState(CPDF_TextState TextState)
    602 {
    603     m_TextState = TextState;
    604     CalcPositionData(NULL, NULL, 0);
    605 }
    606 CPDF_ShadingObject::CPDF_ShadingObject()
    607 {
    608     m_pShading = NULL;
    609     m_Type = PDFPAGE_SHADING;
    610 }
    611 CPDF_ShadingObject::~CPDF_ShadingObject()
    612 {
    613     CPDF_ShadingPattern* pShading = m_pShading;
    614     if (pShading && pShading->m_pDocument) {
    615         pShading->m_pDocument->GetPageData()->ReleasePattern(pShading->m_pShadingObj);
    616     }
    617 }
    618 void CPDF_ShadingObject::CopyData(const CPDF_PageObject* pSrc)
    619 {
    620     CPDF_ShadingObject* pSrcObj = (CPDF_ShadingObject*)pSrc;
    621     m_pShading = pSrcObj->m_pShading;
    622     if (m_pShading && m_pShading->m_pDocument) {
    623         CPDF_DocPageData* pDocPageData = m_pShading->m_pDocument->GetPageData();
    624         m_pShading = (CPDF_ShadingPattern*)pDocPageData->GetPattern(m_pShading->m_pShadingObj, m_pShading->m_bShadingObj, &m_pShading->m_ParentMatrix);
    625     }
    626     m_Matrix = pSrcObj->m_Matrix;
    627 }
    628 void CPDF_ShadingObject::Transform(const CFX_AffineMatrix& matrix)
    629 {
    630     if (!m_ClipPath.IsNull()) {
    631         m_ClipPath.GetModify();
    632         m_ClipPath.Transform(matrix);
    633     }
    634     m_Matrix.Concat(matrix);
    635     if (!m_ClipPath.IsNull()) {
    636         CalcBoundingBox();
    637     } else {
    638         matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
    639     }
    640 }
    641 void CPDF_ShadingObject::CalcBoundingBox()
    642 {
    643     if (m_ClipPath.IsNull()) {
    644         return;
    645     }
    646     CFX_FloatRect rect = m_ClipPath.GetClipBox();
    647     m_Left = rect.left;
    648     m_Bottom = rect.bottom;
    649     m_Right = rect.right;
    650     m_Top = rect.top;
    651 }
    652 CPDF_FormObject::~CPDF_FormObject()
    653 {
    654     if (m_pForm) {
    655         delete m_pForm;
    656     }
    657 }
    658 void CPDF_FormObject::Transform(const CFX_AffineMatrix& matrix)
    659 {
    660     m_FormMatrix.Concat(matrix);
    661     CalcBoundingBox();
    662 }
    663 void CPDF_FormObject::CopyData(const CPDF_PageObject* pSrc)
    664 {
    665     const CPDF_FormObject* pSrcObj = (const CPDF_FormObject*)pSrc;
    666     if (m_pForm) {
    667         delete m_pForm;
    668     }
    669     m_pForm = pSrcObj->m_pForm->Clone();
    670     m_FormMatrix = pSrcObj->m_FormMatrix;
    671 }
    672 void CPDF_FormObject::CalcBoundingBox()
    673 {
    674     CFX_FloatRect form_rect = m_pForm->CalcBoundingBox();
    675     form_rect.Transform(&m_FormMatrix);
    676     m_Left = form_rect.left;
    677     m_Bottom = form_rect.bottom;
    678     m_Right = form_rect.right;
    679     m_Top = form_rect.top;
    680 }
    681 CPDF_PageObjects::CPDF_PageObjects(FX_BOOL bReleaseMembers) : m_ObjectList(128)
    682 {
    683     m_bBackgroundAlphaNeeded = FALSE;
    684     m_bReleaseMembers = bReleaseMembers;
    685     m_ParseState = PDF_CONTENT_NOT_PARSED;
    686     m_pParser = NULL;
    687     m_pFormStream = NULL;
    688     m_pResources = NULL;
    689 }
    690 CPDF_PageObjects::~CPDF_PageObjects()
    691 {
    692     if (m_pParser) {
    693         delete m_pParser;
    694     }
    695     if (!m_bReleaseMembers) {
    696         return;
    697     }
    698     FX_POSITION pos = m_ObjectList.GetHeadPosition();
    699     while (pos) {
    700         CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
    701         if (!pPageObj) {
    702             continue;
    703         }
    704         pPageObj->Release();
    705     }
    706 }
    707 void CPDF_PageObjects::ContinueParse(IFX_Pause* pPause)
    708 {
    709     if (m_pParser == NULL) {
    710         return;
    711     }
    712     m_pParser->Continue(pPause);
    713     if (m_pParser->GetStatus() == CPDF_ContentParser::Done) {
    714         m_ParseState = PDF_CONTENT_PARSED;
    715         delete m_pParser;
    716         m_pParser = NULL;
    717     }
    718 }
    719 int CPDF_PageObjects::EstimateParseProgress() const
    720 {
    721     if (m_pParser == NULL) {
    722         return m_ParseState == PDF_CONTENT_PARSED ? 100 : 0;
    723     }
    724     return m_pParser->EstimateProgress();
    725 }
    726 FX_POSITION CPDF_PageObjects::InsertObject(FX_POSITION posInsertAfter, CPDF_PageObject* pNewObject)
    727 {
    728     if (posInsertAfter == NULL) {
    729         return m_ObjectList.AddHead(pNewObject);
    730     } else {
    731         return m_ObjectList.InsertAfter(posInsertAfter, pNewObject);
    732     }
    733 }
    734 int CPDF_PageObjects::GetObjectIndex(CPDF_PageObject* pObj) const
    735 {
    736     int index = 0;
    737     FX_POSITION pos = m_ObjectList.GetHeadPosition();
    738     while (pos) {
    739         CPDF_PageObject* pThisObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
    740         if (pThisObj == pObj) {
    741             return index;
    742         }
    743         index ++;
    744     }
    745     return -1;
    746 }
    747 CPDF_PageObject* CPDF_PageObjects::GetObjectByIndex(int index) const
    748 {
    749     FX_POSITION pos = m_ObjectList.FindIndex(index);
    750     if (pos == NULL) {
    751         return NULL;
    752     }
    753     return (CPDF_PageObject*)m_ObjectList.GetAt(pos);
    754 }
    755 void CPDF_PageObjects::Transform(const CFX_AffineMatrix& matrix)
    756 {
    757     FX_POSITION pos = m_ObjectList.GetHeadPosition();
    758     while (pos) {
    759         CPDF_PageObject* pObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
    760         pObj->Transform(matrix);
    761     }
    762 }
    763 CFX_FloatRect CPDF_PageObjects::CalcBoundingBox() const
    764 {
    765     if (m_ObjectList.GetCount() == 0) {
    766         return CFX_FloatRect(0, 0, 0, 0);
    767     }
    768     FX_FLOAT left, right, top, bottom;
    769     left = bottom = 1000000 * 1.0f;
    770     right = top = -1000000 * 1.0f;
    771     FX_POSITION pos = m_ObjectList.GetHeadPosition();
    772     while (pos) {
    773         CPDF_PageObject* pObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
    774         if (left > pObj->m_Left) {
    775             left = pObj->m_Left;
    776         }
    777         if (right < pObj->m_Right) {
    778             right = pObj->m_Right;
    779         }
    780         if (top < pObj->m_Top) {
    781             top = pObj->m_Top;
    782         }
    783         if (bottom > pObj->m_Bottom) {
    784             bottom = pObj->m_Bottom;
    785         }
    786     }
    787     return CFX_FloatRect(left, bottom, right, top);
    788 }
    789 void CPDF_PageObjects::LoadTransInfo()
    790 {
    791     if (m_pFormDict == NULL) {
    792         return;
    793     }
    794     CPDF_Dictionary* pGroup = m_pFormDict->GetDict(FX_BSTRC("Group"));
    795     if (pGroup == NULL) {
    796         return;
    797     }
    798     if (pGroup->GetString(FX_BSTRC("S")) != FX_BSTRC("Transparency")) {
    799         return;
    800     }
    801     m_Transparency |= PDFTRANS_GROUP;
    802     if (pGroup->GetInteger(FX_BSTRC("I"))) {
    803         m_Transparency |= PDFTRANS_ISOLATED;
    804     }
    805     if (pGroup->GetInteger(FX_BSTRC("K"))) {
    806         m_Transparency |= PDFTRANS_KNOCKOUT;
    807     }
    808 }
    809 void CPDF_PageObjects::ClearCacheObjects()
    810 {
    811     m_ParseState = PDF_CONTENT_NOT_PARSED;
    812     if (m_pParser) {
    813         delete m_pParser;
    814     }
    815     m_pParser = NULL;
    816     if (m_bReleaseMembers) {
    817         FX_POSITION pos = m_ObjectList.GetHeadPosition();
    818         while (pos) {
    819             CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
    820             if (!pPageObj) {
    821                 continue;
    822             }
    823             pPageObj->Release();
    824         }
    825     }
    826     m_ObjectList.RemoveAll();
    827 }
    828 CPDF_Page::CPDF_Page()
    829 {
    830     m_pPageRender = NULL;
    831 }
    832 void CPDF_Page::Load(CPDF_Document* pDocument, CPDF_Dictionary* pPageDict, FX_BOOL bPageCache)
    833 {
    834     m_pDocument = (CPDF_Document*)pDocument;
    835     m_pFormDict = pPageDict;
    836     if (bPageCache) {
    837         m_pPageRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreatePageCache(this);
    838     }
    839     if (pPageDict == NULL) {
    840         m_PageWidth = m_PageHeight = 100 * 1.0f;
    841         m_pPageResources = m_pResources = NULL;
    842         return;
    843     }
    844     m_pResources = GetPageAttr(FX_BSTRC("Resources"))->GetDict();
    845     m_pPageResources = m_pResources;
    846     CPDF_Object* pRotate = GetPageAttr(FX_BSTRC("Rotate"));
    847     int rotate = 0;
    848     if (pRotate) {
    849         rotate = pRotate->GetInteger() / 90 % 4;
    850     }
    851     if (rotate < 0) {
    852         rotate += 4;
    853     }
    854     CPDF_Array* pMediaBox, *pCropBox;
    855     pMediaBox = (CPDF_Array*)GetPageAttr(FX_BSTRC("MediaBox"));
    856     CFX_FloatRect mediabox;
    857     if (pMediaBox) {
    858         mediabox = pMediaBox->GetRect();
    859         mediabox.Normalize();
    860     }
    861     if (mediabox.IsEmpty()) {
    862         mediabox = CFX_FloatRect(0, 0, 612, 792);
    863     }
    864     pCropBox = (CPDF_Array*)GetPageAttr(FX_BSTRC("CropBox"));
    865     if (pCropBox) {
    866         m_BBox = pCropBox->GetRect();
    867         m_BBox.Normalize();
    868     }
    869     if (m_BBox.IsEmpty()) {
    870         m_BBox = mediabox;
    871     } else {
    872         m_BBox.Intersect(mediabox);
    873     }
    874     if (rotate % 2) {
    875         m_PageHeight = m_BBox.right - m_BBox.left;
    876         m_PageWidth = m_BBox.top - m_BBox.bottom;
    877     } else {
    878         m_PageWidth = m_BBox.right - m_BBox.left;
    879         m_PageHeight = m_BBox.top - m_BBox.bottom;
    880     }
    881     switch (rotate) {
    882         case 0:
    883             m_PageMatrix.Set(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
    884             break;
    885         case 1:
    886             m_PageMatrix.Set(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
    887             break;
    888         case 2:
    889             m_PageMatrix.Set(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
    890             break;
    891         case 3:
    892             m_PageMatrix.Set(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
    893             break;
    894     }
    895     m_Transparency = PDFTRANS_ISOLATED;
    896     LoadTransInfo();
    897 }
    898 void CPDF_Page::StartParse(CPDF_ParseOptions* pOptions, FX_BOOL bReParse)
    899 {
    900     if (bReParse) {
    901         ClearCacheObjects();
    902     }
    903     if (m_ParseState == PDF_CONTENT_PARSED || m_ParseState == PDF_CONTENT_PARSING) {
    904         return;
    905     }
    906     m_pParser = FX_NEW CPDF_ContentParser;
    907     m_pParser->Start(this, pOptions);
    908     m_ParseState = PDF_CONTENT_PARSING;
    909 }
    910 void CPDF_Page::ParseContent(CPDF_ParseOptions* pOptions, FX_BOOL bReParse)
    911 {
    912     StartParse(pOptions, bReParse);
    913     ContinueParse(NULL);
    914 }
    915 CPDF_Page::~CPDF_Page()
    916 {
    917     if (m_pPageRender) {
    918         CPDF_RenderModuleDef* pModule = CPDF_ModuleMgr::Get()->GetRenderModule();
    919         pModule->DestroyPageCache(m_pPageRender);
    920     }
    921 }
    922 CPDF_Object* FPDFAPI_GetPageAttr(CPDF_Dictionary* pPageDict, FX_BSTR name)
    923 {
    924     int level = 0;
    925     while (1) {
    926         CPDF_Object* pObj = pPageDict->GetElementValue(name);
    927         if (pObj) {
    928             return pObj;
    929         }
    930         CPDF_Dictionary* pParent = pPageDict->GetDict(FX_BSTRC("Parent"));
    931         if (!pParent || pParent == pPageDict) {
    932             return NULL;
    933         }
    934         pPageDict = pParent;
    935         level ++;
    936         if (level == 1000) {
    937             return NULL;
    938         }
    939     }
    940 }
    941 CPDF_Object* CPDF_Page::GetPageAttr(FX_BSTR name) const
    942 {
    943     return FPDFAPI_GetPageAttr(m_pFormDict, name);
    944 }
    945 CPDF_Form::CPDF_Form(CPDF_Document* pDoc, CPDF_Dictionary* pPageResources, CPDF_Stream* pFormStream, CPDF_Dictionary* pParentResources)
    946 {
    947     m_pDocument = pDoc;
    948     m_pFormStream = pFormStream;
    949     m_pFormDict = pFormStream->GetDict();
    950     m_pResources = m_pFormDict->GetDict(FX_BSTRC("Resources"));
    951     m_pPageResources = pPageResources;
    952     if (m_pResources == NULL) {
    953         m_pResources = pParentResources;
    954     }
    955     if (m_pResources == NULL) {
    956         m_pResources = pPageResources;
    957     }
    958     m_Transparency = 0;
    959     LoadTransInfo();
    960 }
    961 CPDF_Form::~CPDF_Form()
    962 {
    963 }
    964 void CPDF_Form::StartParse(CPDF_AllStates* pGraphicStates, CFX_AffineMatrix* pParentMatrix,
    965                            CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level)
    966 {
    967     if (m_ParseState == PDF_CONTENT_PARSED || m_ParseState == PDF_CONTENT_PARSING) {
    968         return;
    969     }
    970     m_pParser = FX_NEW CPDF_ContentParser;
    971     m_pParser->Start(this, pGraphicStates, pParentMatrix, pType3Char, pOptions, level);
    972     m_ParseState = PDF_CONTENT_PARSING;
    973 }
    974 void CPDF_Form::ParseContent(CPDF_AllStates* pGraphicStates, CFX_AffineMatrix* pParentMatrix,
    975                              CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level)
    976 {
    977     StartParse(pGraphicStates, pParentMatrix, pType3Char, pOptions, level);
    978     ContinueParse(NULL);
    979 }
    980 CPDF_Form* CPDF_Form::Clone() const
    981 {
    982     CPDF_Form* pClone = FX_NEW CPDF_Form(m_pDocument, m_pPageResources, m_pFormStream, m_pResources);
    983     FX_POSITION pos = m_ObjectList.GetHeadPosition();
    984     while (pos) {
    985         CPDF_PageObject* pObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
    986         pClone->m_ObjectList.AddTail(pObj->Clone());
    987     }
    988     return pClone;
    989 }
    990 void CPDF_Page::GetDisplayMatrix(CFX_AffineMatrix& matrix, int xPos, int yPos,
    991                                  int xSize, int ySize, int iRotate) const
    992 {
    993     if (m_PageWidth == 0 || m_PageHeight == 0) {
    994         return;
    995     }
    996     CFX_AffineMatrix display_matrix;
    997     int x0, y0, x1, y1, x2, y2;
    998     iRotate %= 4;
    999     switch (iRotate) {
   1000         case 0:
   1001             x0 = xPos;
   1002             y0 = yPos + ySize;
   1003             x1 = xPos;
   1004             y1 = yPos;
   1005             x2 = xPos + xSize;
   1006             y2 = yPos + ySize;
   1007             break;
   1008         case 1:
   1009             x0 = xPos;
   1010             y0 = yPos;
   1011             x1 = xPos + xSize;
   1012             y1 = yPos;
   1013             x2 = xPos;
   1014             y2 = yPos + ySize;
   1015             break;
   1016         case 2:
   1017             x0 = xPos + xSize;
   1018             y0 = yPos;
   1019             x1 = xPos + xSize;
   1020             y1 = yPos + ySize;
   1021             x2 = xPos;
   1022             y2 = yPos;
   1023             break;
   1024         case 3:
   1025             x0 = xPos + xSize;
   1026             y0 = yPos + ySize;
   1027             x1 = xPos;
   1028             y1 = yPos + ySize;
   1029             x2 = xPos + xSize;
   1030             y2 = yPos;
   1031             break;
   1032     }
   1033     display_matrix.Set(FXSYS_Div((FX_FLOAT)(x2 - x0), m_PageWidth),
   1034                        FXSYS_Div((FX_FLOAT)(y2 - y0), m_PageWidth),
   1035                        FXSYS_Div((FX_FLOAT)(x1 - x0), m_PageHeight),
   1036                        FXSYS_Div((FX_FLOAT)(y1 - y0), m_PageHeight),
   1037                        (FX_FLOAT)x0, (FX_FLOAT)y0);
   1038     matrix = m_PageMatrix;
   1039     matrix.Concat(display_matrix);
   1040 }
   1041 CPDF_ParseOptions::CPDF_ParseOptions()
   1042 {
   1043     m_bTextOnly = FALSE;
   1044     m_bMarkedContent = TRUE;
   1045     m_bSeparateForm = TRUE;
   1046     m_bDecodeInlineImage = FALSE;
   1047 }
   1048