Home | History | Annotate | Download | only in fpdfdoc
      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/fpdfdoc/csection.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "core/fpdfdoc/cline.h"
     12 #include "core/fpdfdoc/cpdf_variabletext.h"
     13 #include "core/fpdfdoc/cpvt_wordinfo.h"
     14 #include "third_party/base/ptr_util.h"
     15 #include "third_party/base/stl_util.h"
     16 
     17 CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {}
     18 
     19 CSection::~CSection() {}
     20 
     21 void CSection::ResetAll() {
     22   m_WordArray.clear();
     23   m_LineArray.clear();
     24 }
     25 
     26 void CSection::ResetLinePlace() {
     27   int32_t i = 0;
     28   for (auto& pLine : m_LineArray) {
     29     pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1);
     30     ++i;
     31   }
     32 }
     33 
     34 CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place,
     35                                  const CPVT_WordInfo& wordinfo) {
     36   int32_t nWordIndex = pdfium::clamp(
     37       place.nWordIndex, 0, pdfium::CollectionSize<int32_t>(m_WordArray));
     38   m_WordArray.insert(m_WordArray.begin() + nWordIndex,
     39                      pdfium::MakeUnique<CPVT_WordInfo>(wordinfo));
     40   return place;
     41 }
     42 
     43 CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo& lineinfo) {
     44   m_LineArray.push_back(pdfium::MakeUnique<CLine>(lineinfo));
     45   return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.size() - 1, -1);
     46 }
     47 
     48 CPVT_FloatRect CSection::Rearrange() {
     49   if (m_pVT->GetCharArray() > 0)
     50     return CTypeset(this).CharArray();
     51   return CTypeset(this).Typeset();
     52 }
     53 
     54 CFX_SizeF CSection::GetSectionSize(float fFontSize) {
     55   return CTypeset(this).GetEditSize(fFontSize);
     56 }
     57 
     58 CPVT_WordPlace CSection::GetBeginWordPlace() const {
     59   if (m_LineArray.empty())
     60     return SecPlace;
     61   return m_LineArray.front()->GetBeginWordPlace();
     62 }
     63 
     64 CPVT_WordPlace CSection::GetEndWordPlace() const {
     65   if (m_LineArray.empty())
     66     return SecPlace;
     67   return m_LineArray.back()->GetEndWordPlace();
     68 }
     69 
     70 CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace& place) const {
     71   if (place.nLineIndex < 0)
     72     return GetBeginWordPlace();
     73 
     74   if (place.nLineIndex >= pdfium::CollectionSize<int32_t>(m_LineArray))
     75     return GetEndWordPlace();
     76 
     77   CLine* pLine = m_LineArray[place.nLineIndex].get();
     78   if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex)
     79     return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
     80 
     81   if (place.nWordIndex >= pLine->m_LineInfo.nBeginWordIndex)
     82     return pLine->GetPrevWordPlace(place);
     83 
     84   if (!pdfium::IndexInBounds(m_LineArray, place.nLineIndex - 1))
     85     return place;
     86 
     87   return m_LineArray[place.nLineIndex - 1]->GetEndWordPlace();
     88 }
     89 
     90 CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace& place) const {
     91   if (place.nLineIndex < 0)
     92     return GetBeginWordPlace();
     93 
     94   if (place.nLineIndex >= pdfium::CollectionSize<int32_t>(m_LineArray))
     95     return GetEndWordPlace();
     96 
     97   CLine* pLine = m_LineArray[place.nLineIndex].get();
     98   if (place.nWordIndex < pLine->m_LineInfo.nEndWordIndex)
     99     return pLine->GetNextWordPlace(place);
    100 
    101   if (!pdfium::IndexInBounds(m_LineArray, place.nLineIndex + 1))
    102     return place;
    103 
    104   return m_LineArray[place.nLineIndex + 1]->GetBeginWordPlace();
    105 }
    106 
    107 void CSection::UpdateWordPlace(CPVT_WordPlace& place) const {
    108   int32_t nLeft = 0;
    109   int32_t nRight = pdfium::CollectionSize<int32_t>(m_LineArray) - 1;
    110   int32_t nMid = (nLeft + nRight) / 2;
    111   while (nLeft <= nRight) {
    112     CLine* pLine = m_LineArray[nMid].get();
    113     if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
    114       nRight = nMid - 1;
    115       nMid = (nLeft + nRight) / 2;
    116     } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) {
    117       nLeft = nMid + 1;
    118       nMid = (nLeft + nRight) / 2;
    119     } else {
    120       place.nLineIndex = nMid;
    121       return;
    122     }
    123   }
    124 }
    125 
    126 CPVT_WordPlace CSection::SearchWordPlace(const CFX_PointF& point) const {
    127   ASSERT(m_pVT);
    128   CPVT_WordPlace place = GetBeginWordPlace();
    129   bool bUp = true;
    130   bool bDown = true;
    131   int32_t nLeft = 0;
    132   int32_t nRight = pdfium::CollectionSize<int32_t>(m_LineArray) - 1;
    133   int32_t nMid = pdfium::CollectionSize<int32_t>(m_LineArray) / 2;
    134   while (nLeft <= nRight) {
    135     CLine* pLine = m_LineArray[nMid].get();
    136     float fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent -
    137                  m_pVT->GetLineLeading();
    138     float fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent;
    139     if (IsFloatBigger(point.y, fTop))
    140       bUp = false;
    141     if (IsFloatSmaller(point.y, fBottom))
    142       bDown = false;
    143     if (IsFloatSmaller(point.y, fTop)) {
    144       nRight = nMid - 1;
    145       nMid = (nLeft + nRight) / 2;
    146       continue;
    147     }
    148     if (IsFloatBigger(point.y, fBottom)) {
    149       nLeft = nMid + 1;
    150       nMid = (nLeft + nRight) / 2;
    151       continue;
    152     }
    153     place = SearchWordPlace(
    154         point.x,
    155         CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
    156                        pLine->GetEndWordPlace()));
    157     place.nLineIndex = nMid;
    158     return place;
    159   }
    160   if (bUp)
    161     place = GetBeginWordPlace();
    162   if (bDown)
    163     place = GetEndWordPlace();
    164   return place;
    165 }
    166 
    167 CPVT_WordPlace CSection::SearchWordPlace(
    168     float fx,
    169     const CPVT_WordPlace& lineplace) const {
    170   if (!pdfium::IndexInBounds(m_LineArray, lineplace.nLineIndex))
    171     return GetBeginWordPlace();
    172 
    173   CLine* pLine = m_LineArray[lineplace.nLineIndex].get();
    174   return SearchWordPlace(
    175       fx - m_Rect.left,
    176       CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
    177                      pLine->GetEndWordPlace()));
    178 }
    179 
    180 CPVT_WordPlace CSection::SearchWordPlace(float fx,
    181                                          const CPVT_WordRange& range) const {
    182   CPVT_WordPlace wordplace = range.BeginPos;
    183   wordplace.nWordIndex = -1;
    184   if (!m_pVT) {
    185     return wordplace;
    186   }
    187   int32_t nLeft = range.BeginPos.nWordIndex;
    188   int32_t nRight = range.EndPos.nWordIndex + 1;
    189   int32_t nMid = (nLeft + nRight) / 2;
    190   while (nLeft < nRight) {
    191     if (nMid == nLeft)
    192       break;
    193     if (nMid == nRight) {
    194       nMid--;
    195       break;
    196     }
    197     if (!pdfium::IndexInBounds(m_WordArray, nMid))
    198       break;
    199     CPVT_WordInfo* pWord = m_WordArray[nMid].get();
    200     if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
    201       nLeft = nMid;
    202       nMid = (nLeft + nRight) / 2;
    203       continue;
    204     }
    205     nRight = nMid;
    206     nMid = (nLeft + nRight) / 2;
    207   }
    208   if (pdfium::IndexInBounds(m_WordArray, nMid)) {
    209     CPVT_WordInfo* pWord = m_WordArray[nMid].get();
    210     if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF)
    211       wordplace.nWordIndex = nMid;
    212   }
    213   return wordplace;
    214 }
    215 
    216 void CSection::ClearLeftWords(int32_t nWordIndex) {
    217   for (int32_t i = nWordIndex; i >= 0; i--) {
    218     if (pdfium::IndexInBounds(m_WordArray, i))
    219       m_WordArray.erase(m_WordArray.begin() + i);
    220   }
    221 }
    222 
    223 void CSection::ClearRightWords(int32_t nWordIndex) {
    224   int32_t sz = pdfium::CollectionSize<int32_t>(m_WordArray);
    225   for (int32_t i = sz - 1; i > nWordIndex; i--) {
    226     if (pdfium::IndexInBounds(m_WordArray, i))
    227       m_WordArray.erase(m_WordArray.begin() + i);
    228   }
    229 }
    230 
    231 void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) {
    232   for (int32_t i = nEndIndex; i > nBeginIndex; i--) {
    233     if (pdfium::IndexInBounds(m_WordArray, i))
    234       m_WordArray.erase(m_WordArray.begin() + i);
    235   }
    236 }
    237 
    238 void CSection::ClearWords(const CPVT_WordRange& PlaceRange) {
    239   CPVT_WordPlace SecBeginPos = GetBeginWordPlace();
    240   CPVT_WordPlace SecEndPos = GetEndWordPlace();
    241   if (PlaceRange.BeginPos >= SecBeginPos) {
    242     if (PlaceRange.EndPos <= SecEndPos) {
    243       ClearMidWords(PlaceRange.BeginPos.nWordIndex,
    244                     PlaceRange.EndPos.nWordIndex);
    245     } else {
    246       ClearRightWords(PlaceRange.BeginPos.nWordIndex);
    247     }
    248   } else if (PlaceRange.EndPos <= SecEndPos) {
    249     ClearLeftWords(PlaceRange.EndPos.nWordIndex);
    250   } else {
    251     m_WordArray.clear();
    252   }
    253 }
    254 
    255 void CSection::ClearWord(const CPVT_WordPlace& place) {
    256   if (pdfium::IndexInBounds(m_WordArray, place.nWordIndex))
    257     m_WordArray.erase(m_WordArray.begin() + place.nWordIndex);
    258 }
    259