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/cpvt_wordinfo.h"
     13 
     14 CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {}
     15 
     16 CSection::~CSection() {
     17   ResetAll();
     18 }
     19 
     20 void CSection::ResetAll() {
     21   ResetWordArray();
     22   ResetLineArray();
     23 }
     24 
     25 void CSection::ResetLineArray() {
     26   m_LineArray.RemoveAll();
     27 }
     28 
     29 void CSection::ResetWordArray() {
     30   for (int32_t i = 0, sz = m_WordArray.GetSize(); i < sz; i++) {
     31     delete m_WordArray.GetAt(i);
     32   }
     33   m_WordArray.RemoveAll();
     34 }
     35 
     36 void CSection::ResetLinePlace() {
     37   for (int32_t i = 0, sz = m_LineArray.GetSize(); i < sz; i++) {
     38     if (CLine* pLine = m_LineArray.GetAt(i)) {
     39       pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1);
     40     }
     41   }
     42 }
     43 
     44 CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place,
     45                                  const CPVT_WordInfo& wordinfo) {
     46   CPVT_WordInfo* pWord = new CPVT_WordInfo(wordinfo);
     47   int32_t nWordIndex =
     48       std::max(std::min(place.nWordIndex, m_WordArray.GetSize()), 0);
     49   if (nWordIndex == m_WordArray.GetSize()) {
     50     m_WordArray.Add(pWord);
     51   } else {
     52     m_WordArray.InsertAt(nWordIndex, pWord);
     53   }
     54   return place;
     55 }
     56 
     57 CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo& lineinfo) {
     58   return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.Add(lineinfo), -1);
     59 }
     60 
     61 CPVT_FloatRect CSection::Rearrange() {
     62   if (m_pVT->m_nCharArray > 0) {
     63     return CTypeset(this).CharArray();
     64   }
     65   return CTypeset(this).Typeset();
     66 }
     67 
     68 CFX_SizeF CSection::GetSectionSize(FX_FLOAT fFontSize) {
     69   return CTypeset(this).GetEditSize(fFontSize);
     70 }
     71 
     72 CPVT_WordPlace CSection::GetBeginWordPlace() const {
     73   if (CLine* pLine = m_LineArray.GetAt(0)) {
     74     return pLine->GetBeginWordPlace();
     75   }
     76   return SecPlace;
     77 }
     78 
     79 CPVT_WordPlace CSection::GetEndWordPlace() const {
     80   if (CLine* pLine = m_LineArray.GetAt(m_LineArray.GetSize() - 1)) {
     81     return pLine->GetEndWordPlace();
     82   }
     83   return SecPlace;
     84 }
     85 
     86 CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace& place) const {
     87   if (place.nLineIndex < 0) {
     88     return GetBeginWordPlace();
     89   }
     90   if (place.nLineIndex >= m_LineArray.GetSize()) {
     91     return GetEndWordPlace();
     92   }
     93   if (CLine* pLine = m_LineArray.GetAt(place.nLineIndex)) {
     94     if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex) {
     95       return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
     96     }
     97     if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
     98       if (CLine* pPrevLine = m_LineArray.GetAt(place.nLineIndex - 1)) {
     99         return pPrevLine->GetEndWordPlace();
    100       }
    101     } else {
    102       return pLine->GetPrevWordPlace(place);
    103     }
    104   }
    105   return place;
    106 }
    107 
    108 CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace& place) const {
    109   if (place.nLineIndex < 0) {
    110     return GetBeginWordPlace();
    111   }
    112   if (place.nLineIndex >= m_LineArray.GetSize()) {
    113     return GetEndWordPlace();
    114   }
    115   if (CLine* pLine = m_LineArray.GetAt(place.nLineIndex)) {
    116     if (place.nWordIndex >= pLine->m_LineInfo.nEndWordIndex) {
    117       if (CLine* pNextLine = m_LineArray.GetAt(place.nLineIndex + 1)) {
    118         return pNextLine->GetBeginWordPlace();
    119       }
    120     } else {
    121       return pLine->GetNextWordPlace(place);
    122     }
    123   }
    124   return place;
    125 }
    126 
    127 void CSection::UpdateWordPlace(CPVT_WordPlace& place) const {
    128   int32_t nLeft = 0;
    129   int32_t nRight = m_LineArray.GetSize() - 1;
    130   int32_t nMid = (nLeft + nRight) / 2;
    131   while (nLeft <= nRight) {
    132     if (CLine* pLine = m_LineArray.GetAt(nMid)) {
    133       if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
    134         nRight = nMid - 1;
    135         nMid = (nLeft + nRight) / 2;
    136       } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) {
    137         nLeft = nMid + 1;
    138         nMid = (nLeft + nRight) / 2;
    139       } else {
    140         place.nLineIndex = nMid;
    141         return;
    142       }
    143     } else {
    144       break;
    145     }
    146   }
    147 }
    148 
    149 CPVT_WordPlace CSection::SearchWordPlace(const CFX_PointF& point) const {
    150   ASSERT(m_pVT);
    151   CPVT_WordPlace place = GetBeginWordPlace();
    152   bool bUp = true;
    153   bool bDown = true;
    154   int32_t nLeft = 0;
    155   int32_t nRight = m_LineArray.GetSize() - 1;
    156   int32_t nMid = m_LineArray.GetSize() / 2;
    157   FX_FLOAT fTop = 0;
    158   FX_FLOAT fBottom = 0;
    159   while (nLeft <= nRight) {
    160     if (CLine* pLine = m_LineArray.GetAt(nMid)) {
    161       fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent -
    162              m_pVT->GetLineLeading(m_SecInfo);
    163       fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent;
    164       if (IsFloatBigger(point.y, fTop)) {
    165         bUp = false;
    166       }
    167       if (IsFloatSmaller(point.y, fBottom)) {
    168         bDown = false;
    169       }
    170       if (IsFloatSmaller(point.y, fTop)) {
    171         nRight = nMid - 1;
    172         nMid = (nLeft + nRight) / 2;
    173         continue;
    174       } else if (IsFloatBigger(point.y, fBottom)) {
    175         nLeft = nMid + 1;
    176         nMid = (nLeft + nRight) / 2;
    177         continue;
    178       } else {
    179         place = SearchWordPlace(
    180             point.x,
    181             CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
    182                            pLine->GetEndWordPlace()));
    183         place.nLineIndex = nMid;
    184         return place;
    185       }
    186     }
    187   }
    188   if (bUp) {
    189     place = GetBeginWordPlace();
    190   }
    191   if (bDown) {
    192     place = GetEndWordPlace();
    193   }
    194   return place;
    195 }
    196 
    197 CPVT_WordPlace CSection::SearchWordPlace(
    198     FX_FLOAT fx,
    199     const CPVT_WordPlace& lineplace) const {
    200   if (CLine* pLine = m_LineArray.GetAt(lineplace.nLineIndex)) {
    201     return SearchWordPlace(
    202         fx - m_SecInfo.rcSection.left,
    203         CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
    204                        pLine->GetEndWordPlace()));
    205   }
    206   return GetBeginWordPlace();
    207 }
    208 
    209 CPVT_WordPlace CSection::SearchWordPlace(FX_FLOAT fx,
    210                                          const CPVT_WordRange& range) const {
    211   CPVT_WordPlace wordplace = range.BeginPos;
    212   wordplace.nWordIndex = -1;
    213   if (!m_pVT) {
    214     return wordplace;
    215   }
    216   int32_t nLeft = range.BeginPos.nWordIndex;
    217   int32_t nRight = range.EndPos.nWordIndex + 1;
    218   int32_t nMid = (nLeft + nRight) / 2;
    219   while (nLeft < nRight) {
    220     if (nMid == nLeft) {
    221       break;
    222     }
    223     if (nMid == nRight) {
    224       nMid--;
    225       break;
    226     }
    227     if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) {
    228       if (fx >
    229           pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
    230         nLeft = nMid;
    231         nMid = (nLeft + nRight) / 2;
    232         continue;
    233       } else {
    234         nRight = nMid;
    235         nMid = (nLeft + nRight) / 2;
    236         continue;
    237       }
    238     } else {
    239       break;
    240     }
    241   }
    242   if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) {
    243     if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
    244       wordplace.nWordIndex = nMid;
    245     }
    246   }
    247   return wordplace;
    248 }
    249 
    250 void CSection::ClearLeftWords(int32_t nWordIndex) {
    251   for (int32_t i = nWordIndex; i >= 0; i--) {
    252     delete m_WordArray.GetAt(i);
    253     m_WordArray.RemoveAt(i);
    254   }
    255 }
    256 
    257 void CSection::ClearRightWords(int32_t nWordIndex) {
    258   for (int32_t i = m_WordArray.GetSize() - 1; i > nWordIndex; i--) {
    259     delete m_WordArray.GetAt(i);
    260     m_WordArray.RemoveAt(i);
    261   }
    262 }
    263 
    264 void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) {
    265   for (int32_t i = nEndIndex; i > nBeginIndex; i--) {
    266     delete m_WordArray.GetAt(i);
    267     m_WordArray.RemoveAt(i);
    268   }
    269 }
    270 
    271 void CSection::ClearWords(const CPVT_WordRange& PlaceRange) {
    272   CPVT_WordPlace SecBeginPos = GetBeginWordPlace();
    273   CPVT_WordPlace SecEndPos = GetEndWordPlace();
    274   if (PlaceRange.BeginPos.WordCmp(SecBeginPos) >= 0) {
    275     if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
    276       ClearMidWords(PlaceRange.BeginPos.nWordIndex,
    277                     PlaceRange.EndPos.nWordIndex);
    278     } else {
    279       ClearRightWords(PlaceRange.BeginPos.nWordIndex);
    280     }
    281   } else if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
    282     ClearLeftWords(PlaceRange.EndPos.nWordIndex);
    283   } else {
    284     ResetWordArray();
    285   }
    286 }
    287 
    288 void CSection::ClearWord(const CPVT_WordPlace& place) {
    289   delete m_WordArray.GetAt(place.nWordIndex);
    290   m_WordArray.RemoveAt(place.nWordIndex);
    291 }
    292