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