Home | History | Annotate | Download | only in page
      1 // Copyright 2016 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fpdfapi/page/cpdf_textobject.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "core/fpdfapi/font/cpdf_cidfont.h"
     12 #include "core/fpdfapi/font/cpdf_font.h"
     13 #include "third_party/base/ptr_util.h"
     14 #include "third_party/base/stl_util.h"
     15 
     16 CPDF_TextObjectItem::CPDF_TextObjectItem() : m_CharCode(0) {}
     17 
     18 CPDF_TextObjectItem::~CPDF_TextObjectItem() = default;
     19 
     20 CPDF_TextObject::CPDF_TextObject() {}
     21 
     22 CPDF_TextObject::~CPDF_TextObject() {}
     23 
     24 int CPDF_TextObject::CountItems() const {
     25   return pdfium::CollectionSize<int>(m_CharCodes);
     26 }
     27 
     28 void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const {
     29   pInfo->m_CharCode = m_CharCodes[index];
     30   pInfo->m_Origin = CFX_PointF(index ? m_CharPos[index - 1] : 0, 0);
     31   if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode)
     32     return;
     33 
     34   CPDF_Font* pFont = m_TextState.GetFont();
     35   if (!pFont->IsCIDFont())
     36     return;
     37   if (!pFont->AsCIDFont()->IsVertWriting())
     38     return;
     39 
     40   uint16_t CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode);
     41   pInfo->m_Origin = CFX_PointF(0, pInfo->m_Origin.x);
     42 
     43   short vx;
     44   short vy;
     45   pFont->AsCIDFont()->GetVertOrigin(CID, vx, vy);
     46 
     47   FX_FLOAT fontsize = m_TextState.GetFontSize();
     48   pInfo->m_Origin.x -= fontsize * vx / 1000;
     49   pInfo->m_Origin.y -= fontsize * vy / 1000;
     50 }
     51 
     52 int CPDF_TextObject::CountChars() const {
     53   int count = 0;
     54   for (uint32_t charcode : m_CharCodes) {
     55     if (charcode != CPDF_Font::kInvalidCharCode)
     56       count++;
     57   }
     58   return count;
     59 }
     60 
     61 void CPDF_TextObject::GetCharInfo(int index,
     62                                   uint32_t* charcode,
     63                                   FX_FLOAT* kerning) const {
     64   int count = 0;
     65   for (size_t i = 0; i < m_CharCodes.size(); ++i) {
     66     if (m_CharCodes[i] == CPDF_Font::kInvalidCharCode)
     67       continue;
     68     if (count++ != index)
     69       continue;
     70     *charcode = m_CharCodes[i];
     71     if (i == m_CharCodes.size() - 1 ||
     72         m_CharCodes[i + 1] != CPDF_Font::kInvalidCharCode) {
     73       *kerning = 0;
     74     } else {
     75       *kerning = m_CharPos[i];
     76     }
     77     return;
     78   }
     79 }
     80 
     81 void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const {
     82   int count = 0;
     83   for (int i = 0; i < pdfium::CollectionSize<int>(m_CharCodes); ++i) {
     84     uint32_t charcode = m_CharCodes[i];
     85     if (charcode == CPDF_Font::kInvalidCharCode)
     86       continue;
     87     if (count++ != index)
     88       continue;
     89     GetItemInfo(i, pInfo);
     90     break;
     91   }
     92 }
     93 
     94 std::unique_ptr<CPDF_TextObject> CPDF_TextObject::Clone() const {
     95   auto obj = pdfium::MakeUnique<CPDF_TextObject>();
     96   obj->CopyData(this);
     97   obj->m_CharCodes = m_CharCodes;
     98   obj->m_CharPos = m_CharPos;
     99   obj->m_Pos = m_Pos;
    100   return obj;
    101 }
    102 
    103 CPDF_PageObject::Type CPDF_TextObject::GetType() const {
    104   return TEXT;
    105 }
    106 
    107 void CPDF_TextObject::Transform(const CFX_Matrix& matrix) {
    108   CFX_Matrix text_matrix = GetTextMatrix();
    109   text_matrix.Concat(matrix);
    110 
    111   FX_FLOAT* pTextMatrix = m_TextState.GetMutableMatrix();
    112   pTextMatrix[0] = text_matrix.a;
    113   pTextMatrix[1] = text_matrix.c;
    114   pTextMatrix[2] = text_matrix.b;
    115   pTextMatrix[3] = text_matrix.d;
    116   m_Pos = CFX_PointF(text_matrix.e, text_matrix.f);
    117   CalcPositionData(0);
    118 }
    119 
    120 bool CPDF_TextObject::IsText() const {
    121   return true;
    122 }
    123 
    124 CPDF_TextObject* CPDF_TextObject::AsText() {
    125   return this;
    126 }
    127 
    128 const CPDF_TextObject* CPDF_TextObject::AsText() const {
    129   return this;
    130 }
    131 
    132 CFX_Matrix CPDF_TextObject::GetTextMatrix() const {
    133   const FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
    134   return CFX_Matrix(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1],
    135                     pTextMatrix[3], m_Pos.x, m_Pos.y);
    136 }
    137 
    138 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs,
    139                                   const FX_FLOAT* pKerning,
    140                                   int nsegs) {
    141   m_CharCodes.clear();
    142   m_CharPos.clear();
    143   CPDF_Font* pFont = m_TextState.GetFont();
    144   int nChars = 0;
    145   for (int i = 0; i < nsegs; ++i)
    146     nChars += pFont->CountChar(pStrs[i].c_str(), pStrs[i].GetLength());
    147   nChars += nsegs - 1;
    148   m_CharCodes.resize(nChars);
    149   m_CharPos.resize(nChars - 1);
    150   int index = 0;
    151   for (int i = 0; i < nsegs; ++i) {
    152     const FX_CHAR* segment = pStrs[i].c_str();
    153     int len = pStrs[i].GetLength();
    154     int offset = 0;
    155     while (offset < len)
    156       m_CharCodes[index++] = pFont->GetNextChar(segment, len, offset);
    157     if (i != nsegs - 1) {
    158       m_CharPos[index - 1] = pKerning[i];
    159       m_CharCodes[index++] = CPDF_Font::kInvalidCharCode;
    160     }
    161   }
    162 }
    163 
    164 void CPDF_TextObject::SetText(const CFX_ByteString& str) {
    165   SetSegments(&str, nullptr, 1);
    166   RecalcPositionData();
    167 }
    168 
    169 FX_FLOAT CPDF_TextObject::GetCharWidth(uint32_t charcode) const {
    170   FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
    171   CPDF_Font* pFont = m_TextState.GetFont();
    172   bool bVertWriting = false;
    173   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
    174   if (pCIDFont)
    175     bVertWriting = pCIDFont->IsVertWriting();
    176   if (!bVertWriting)
    177     return pFont->GetCharWidthF(charcode) * fontsize;
    178 
    179   uint16_t CID = pCIDFont->CIDFromCharCode(charcode);
    180   return pCIDFont->GetVertWidth(CID) * fontsize;
    181 }
    182 
    183 CPDF_Font* CPDF_TextObject::GetFont() const {
    184   return m_TextState.GetFont();
    185 }
    186 
    187 FX_FLOAT CPDF_TextObject::GetFontSize() const {
    188   return m_TextState.GetFontSize();
    189 }
    190 
    191 CFX_PointF CPDF_TextObject::CalcPositionData(FX_FLOAT horz_scale) {
    192   FX_FLOAT curpos = 0;
    193   FX_FLOAT min_x = 10000 * 1.0f;
    194   FX_FLOAT max_x = -10000 * 1.0f;
    195   FX_FLOAT min_y = 10000 * 1.0f;
    196   FX_FLOAT max_y = -10000 * 1.0f;
    197   CPDF_Font* pFont = m_TextState.GetFont();
    198   bool bVertWriting = false;
    199   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
    200   if (pCIDFont)
    201     bVertWriting = pCIDFont->IsVertWriting();
    202 
    203   FX_FLOAT fontsize = m_TextState.GetFontSize();
    204   for (int i = 0; i < pdfium::CollectionSize<int>(m_CharCodes); ++i) {
    205     uint32_t charcode = m_CharCodes[i];
    206     if (i > 0) {
    207       if (charcode == CPDF_Font::kInvalidCharCode) {
    208         curpos -= (m_CharPos[i - 1] * fontsize) / 1000;
    209         continue;
    210       }
    211       m_CharPos[i - 1] = curpos;
    212     }
    213 
    214     FX_RECT char_rect = pFont->GetCharBBox(charcode);
    215     FX_FLOAT charwidth;
    216     if (!bVertWriting) {
    217       min_y = std::min(min_y, static_cast<FX_FLOAT>(
    218                                   std::min(char_rect.top, char_rect.bottom)));
    219       max_y = std::max(max_y, static_cast<FX_FLOAT>(
    220                                   std::max(char_rect.top, char_rect.bottom)));
    221       FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;
    222       FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;
    223       min_x = std::min(min_x, std::min(char_left, char_right));
    224       max_x = std::max(max_x, std::max(char_left, char_right));
    225       charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000;
    226     } else {
    227       uint16_t CID = pCIDFont->CIDFromCharCode(charcode);
    228       short vx;
    229       short vy;
    230       pCIDFont->GetVertOrigin(CID, vx, vy);
    231       char_rect.left -= vx;
    232       char_rect.right -= vx;
    233       char_rect.top -= vy;
    234       char_rect.bottom -= vy;
    235       min_x = std::min(min_x, static_cast<FX_FLOAT>(
    236                                   std::min(char_rect.left, char_rect.right)));
    237       max_x = std::max(max_x, static_cast<FX_FLOAT>(
    238                                   std::max(char_rect.left, char_rect.right)));
    239       FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;
    240       FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;
    241       min_y = std::min(min_y, std::min(char_top, char_bottom));
    242       max_y = std::max(max_y, std::max(char_top, char_bottom));
    243       charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
    244     }
    245     curpos += charwidth;
    246     if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(' ') == 1))
    247       curpos += m_TextState.GetWordSpace();
    248 
    249     curpos += m_TextState.GetCharSpace();
    250   }
    251 
    252   CFX_PointF ret;
    253   if (bVertWriting) {
    254     ret.y = curpos;
    255     min_x = min_x * fontsize / 1000;
    256     max_x = max_x * fontsize / 1000;
    257   } else {
    258     ret.x = curpos * horz_scale;
    259     min_y = min_y * fontsize / 1000;
    260     max_y = max_y * fontsize / 1000;
    261   }
    262 
    263   m_Left = min_x;
    264   m_Right = max_x;
    265   m_Bottom = min_y;
    266   m_Top = max_y;
    267   GetTextMatrix().TransformRect(m_Left, m_Right, m_Top, m_Bottom);
    268 
    269   if (!TextRenderingModeIsStrokeMode(m_TextState.GetTextMode()))
    270     return ret;
    271 
    272   FX_FLOAT half_width = m_GraphState.GetLineWidth() / 2;
    273   m_Left -= half_width;
    274   m_Right += half_width;
    275   m_Top += half_width;
    276   m_Bottom -= half_width;
    277 
    278   return ret;
    279 }
    280 
    281 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y) {
    282   FX_FLOAT dx = x - m_Pos.x;
    283   FX_FLOAT dy = y - m_Pos.y;
    284   m_Pos.x = x;
    285   m_Pos.y = y;
    286   m_Left += dx;
    287   m_Right += dx;
    288   m_Top += dy;
    289   m_Bottom += dy;
    290 }
    291 
    292 void CPDF_TextObject::RecalcPositionData() {
    293   CalcPositionData(1);
    294 }
    295