| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" |
| #include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" |
| #include "core/fpdfdoc/include/cpvt_word.h" |
| #include "core/fpdfdoc/include/ipvt_fontmap.h" |
| #include "fpdfsdk/fxedit/include/fx_edit.h" |
| #include "fpdfsdk/fxedit/include/fxet_edit.h" |
| |
| namespace { |
| |
| CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) { |
| if (strWords.GetLength() > 0) |
| return PDF_EncodeString(strWords) + " Tj\n"; |
| return CFX_ByteString(); |
| } |
| |
| CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap, |
| int32_t nFontIndex, |
| FX_FLOAT fFontSize) { |
| if (!pFontMap) |
| return CFX_ByteString(); |
| |
| CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); |
| if (sFontAlias.GetLength() <= 0 || fFontSize <= 0) |
| return CFX_ByteString(); |
| |
| CFX_ByteTextBuf sRet; |
| sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; |
| return sRet.MakeString(); |
| } |
| |
| } // namespace |
| |
| CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap, |
| int32_t nFontIndex, |
| uint16_t Word, |
| uint16_t SubWord) { |
| CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex); |
| if (!pPDFFont) |
| return CFX_ByteString(); |
| |
| CFX_ByteString sWord; |
| if (SubWord > 0) { |
| Word = SubWord; |
| } else { |
| uint32_t dwCharCode = pPDFFont->IsUnicodeCompatible() |
| ? pPDFFont->CharCodeFromUnicode(Word) |
| : pFontMap->CharCodeFromUnicode(nFontIndex, Word); |
| |
| if (dwCharCode > 0) { |
| pPDFFont->AppendChar(sWord, dwCharCode); |
| return sWord; |
| } |
| } |
| |
| pPDFFont->AppendChar(sWord, Word); |
| return sWord; |
| } |
| |
| CFX_ByteString IFX_Edit::GetEditAppearanceStream(IFX_Edit* pEdit, |
| const CFX_FloatPoint& ptOffset, |
| const CPVT_WordRange* pRange, |
| FX_BOOL bContinuous, |
| uint16_t SubWord) { |
| IFX_Edit_Iterator* pIterator = pEdit->GetIterator(); |
| if (pRange) |
| pIterator->SetAt(pRange->BeginPos); |
| else |
| pIterator->SetAt(0); |
| |
| CFX_ByteTextBuf sEditStream; |
| CFX_ByteTextBuf sWords; |
| int32_t nCurFontIndex = -1; |
| CFX_FloatPoint ptOld(0.0f, 0.0f); |
| CFX_FloatPoint ptNew(0.0f, 0.0f); |
| CPVT_WordPlace oldplace; |
| while (pIterator->NextWord()) { |
| CPVT_WordPlace place = pIterator->GetAt(); |
| |
| if (pRange && place.WordCmp(pRange->EndPos) > 0) |
| break; |
| |
| if (bContinuous) { |
| if (place.LineCmp(oldplace) != 0) { |
| if (sWords.GetSize() > 0) { |
| sEditStream << GetWordRenderString(sWords.MakeString()); |
| sWords.Clear(); |
| } |
| |
| CPVT_Word word; |
| if (pIterator->GetWord(word)) { |
| ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x, |
| word.ptWord.y + ptOffset.y); |
| } else { |
| CPVT_Line line; |
| pIterator->GetLine(line); |
| ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x, |
| line.ptLine.y + ptOffset.y); |
| } |
| |
| if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) { |
| sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y |
| << " Td\n"; |
| |
| ptOld = ptNew; |
| } |
| } |
| |
| CPVT_Word word; |
| if (pIterator->GetWord(word)) { |
| if (word.nFontIndex != nCurFontIndex) { |
| if (sWords.GetSize() > 0) { |
| sEditStream << GetWordRenderString(sWords.MakeString()); |
| sWords.Clear(); |
| } |
| sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex, |
| word.fFontSize); |
| nCurFontIndex = word.nFontIndex; |
| } |
| |
| sWords << GetPDFWordString(pEdit->GetFontMap(), nCurFontIndex, |
| word.Word, SubWord); |
| } |
| |
| oldplace = place; |
| } else { |
| CPVT_Word word; |
| if (pIterator->GetWord(word)) { |
| ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x, |
| word.ptWord.y + ptOffset.y); |
| |
| if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) { |
| sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y |
| << " Td\n"; |
| ptOld = ptNew; |
| } |
| |
| if (word.nFontIndex != nCurFontIndex) { |
| sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex, |
| word.fFontSize); |
| nCurFontIndex = word.nFontIndex; |
| } |
| |
| sEditStream << GetWordRenderString(GetPDFWordString( |
| pEdit->GetFontMap(), nCurFontIndex, word.Word, SubWord)); |
| } |
| } |
| } |
| |
| if (sWords.GetSize() > 0) { |
| sEditStream << GetWordRenderString(sWords.MakeString()); |
| sWords.Clear(); |
| } |
| |
| CFX_ByteTextBuf sAppStream; |
| if (sEditStream.GetSize() > 0) { |
| int32_t nHorzScale = pEdit->GetHorzScale(); |
| if (nHorzScale != 100) { |
| sAppStream << nHorzScale << " Tz\n"; |
| } |
| |
| FX_FLOAT fCharSpace = pEdit->GetCharSpace(); |
| if (!FX_EDIT_IsFloatZero(fCharSpace)) { |
| sAppStream << fCharSpace << " Tc\n"; |
| } |
| |
| sAppStream << sEditStream; |
| } |
| |
| return sAppStream.MakeString(); |
| } |
| |
| CFX_ByteString IFX_Edit::GetSelectAppearanceStream( |
| IFX_Edit* pEdit, |
| const CFX_FloatPoint& ptOffset, |
| const CPVT_WordRange* pRange) { |
| if (!pRange || !pRange->IsExist()) |
| return CFX_ByteString(); |
| |
| IFX_Edit_Iterator* pIterator = pEdit->GetIterator(); |
| pIterator->SetAt(pRange->BeginPos); |
| |
| CFX_ByteTextBuf sRet; |
| while (pIterator->NextWord()) { |
| CPVT_WordPlace place = pIterator->GetAt(); |
| if (place.WordCmp(pRange->EndPos) > 0) |
| break; |
| |
| CPVT_Word word; |
| CPVT_Line line; |
| if (pIterator->GetWord(word) && pIterator->GetLine(line)) { |
| sRet << word.ptWord.x + ptOffset.x << " " |
| << line.ptLine.y + line.fLineDescent << " " << word.fWidth << " " |
| << line.fLineAscent - line.fLineDescent << " re\nf\n"; |
| } |
| } |
| |
| return sRet.MakeString(); |
| } |