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