diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2016-03-14 13:35:12 -0400 |
---|---|---|
committer | Dan Sinclair <dsinclair@chromium.org> | 2016-03-14 13:35:12 -0400 |
commit | 764ec513eecbebd12781bcc96ce81ed5e736ee92 (patch) | |
tree | 12763fde4be1f10ea1183d92185917b2b587e00b /core/fpdfdoc | |
parent | 97da97662417085774f75c26e535c6fbe70266ae (diff) | |
download | pdfium-764ec513eecbebd12781bcc96ce81ed5e736ee92.tar.xz |
Move core/src/ up to core/.
This CL moves the core/src/ files up to core/ and fixes up the include guards,
includes and build files.
R=tsepez@chromium.org
Review URL: https://codereview.chromium.org/1800523005 .
Diffstat (limited to 'core/fpdfdoc')
-rw-r--r-- | core/fpdfdoc/doc_action.cpp | 295 | ||||
-rw-r--r-- | core/fpdfdoc/doc_annot.cpp | 350 | ||||
-rw-r--r-- | core/fpdfdoc/doc_ap.cpp | 936 | ||||
-rw-r--r-- | core/fpdfdoc/doc_basic.cpp | 510 | ||||
-rw-r--r-- | core/fpdfdoc/doc_basic_unittest.cpp | 169 | ||||
-rw-r--r-- | core/fpdfdoc/doc_bookmark.cpp | 95 | ||||
-rw-r--r-- | core/fpdfdoc/doc_form.cpp | 1207 | ||||
-rw-r--r-- | core/fpdfdoc/doc_formcontrol.cpp | 432 | ||||
-rw-r--r-- | core/fpdfdoc/doc_formfield.cpp | 1097 | ||||
-rw-r--r-- | core/fpdfdoc/doc_link.cpp | 92 | ||||
-rw-r--r-- | core/fpdfdoc/doc_metadata.cpp | 29 | ||||
-rw-r--r-- | core/fpdfdoc/doc_ocg.cpp | 284 | ||||
-rw-r--r-- | core/fpdfdoc/doc_tagged.cpp | 440 | ||||
-rw-r--r-- | core/fpdfdoc/doc_utils.cpp | 753 | ||||
-rw-r--r-- | core/fpdfdoc/doc_utils.h | 80 | ||||
-rw-r--r-- | core/fpdfdoc/doc_viewerPreferences.cpp | 54 | ||||
-rw-r--r-- | core/fpdfdoc/doc_vt.cpp | 1825 | ||||
-rw-r--r-- | core/fpdfdoc/doc_vtmodule.cpp | 16 | ||||
-rw-r--r-- | core/fpdfdoc/pdf_vt.h | 554 | ||||
-rw-r--r-- | core/fpdfdoc/tagged_int.h | 106 |
20 files changed, 9324 insertions, 0 deletions
diff --git a/core/fpdfdoc/doc_action.cpp b/core/fpdfdoc/doc_action.cpp new file mode 100644 index 0000000000..0af219e47e --- /dev/null +++ b/core/fpdfdoc/doc_action.cpp @@ -0,0 +1,295 @@ +// 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 <vector> + +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const { + if (!m_pDict) { + return CPDF_Dest(); + } + CFX_ByteString type = m_pDict->GetStringBy("S"); + if (type != "GoTo" && type != "GoToR") { + return CPDF_Dest(); + } + CPDF_Object* pDest = m_pDict->GetElementValue("D"); + if (!pDest) { + return CPDF_Dest(); + } + if (pDest->IsString() || pDest->IsName()) { + CPDF_NameTree name_tree(pDoc, "Dests"); + CFX_ByteStringC name = pDest->GetString(); + return CPDF_Dest(name_tree.LookupNamedDest(pDoc, name)); + } + if (CPDF_Array* pArray = pDest->AsArray()) + return CPDF_Dest(pArray); + return CPDF_Dest(); +} +const FX_CHAR* g_sATypes[] = { + "Unknown", "GoTo", "GoToR", "GoToE", "Launch", + "Thread", "URI", "Sound", "Movie", "Hide", + "Named", "SubmitForm", "ResetForm", "ImportData", "JavaScript", + "SetOCGState", "Rendition", "Trans", "GoTo3DView", ""}; +CPDF_Action::ActionType CPDF_Action::GetType() const { + ActionType eType = Unknown; + if (m_pDict) { + CFX_ByteString csType = m_pDict->GetStringBy("S"); + if (!csType.IsEmpty()) { + int i = 0; + while (g_sATypes[i][0] != '\0') { + if (csType == g_sATypes[i]) { + return (ActionType)i; + } + i++; + } + } + } + return eType; +} +CFX_WideString CPDF_Action::GetFilePath() const { + CFX_ByteString type = m_pDict->GetStringBy("S"); + if (type != "GoToR" && type != "Launch" && type != "SubmitForm" && + type != "ImportData") { + return CFX_WideString(); + } + CPDF_Object* pFile = m_pDict->GetElementValue("F"); + CFX_WideString path; + if (!pFile) { + if (type == "Launch") { + CPDF_Dictionary* pWinDict = m_pDict->GetDictBy("Win"); + if (pWinDict) { + return CFX_WideString::FromLocal(pWinDict->GetStringBy("F")); + } + } + return path; + } + CPDF_FileSpec filespec(pFile); + filespec.GetFileName(&path); + return path; +} +CFX_ByteString CPDF_Action::GetURI(CPDF_Document* pDoc) const { + CFX_ByteString csURI; + if (!m_pDict) { + return csURI; + } + if (m_pDict->GetStringBy("S") != "URI") { + return csURI; + } + csURI = m_pDict->GetStringBy("URI"); + CPDF_Dictionary* pRoot = pDoc->GetRoot(); + CPDF_Dictionary* pURI = pRoot->GetDictBy("URI"); + if (pURI) { + if (csURI.Find(":", 0) < 1) { + csURI = pURI->GetStringBy("Base") + csURI; + } + } + return csURI; +} +FX_DWORD CPDF_ActionFields::GetFieldsCount() const { + if (!m_pAction) { + return 0; + } + CPDF_Dictionary* pDict = m_pAction->GetDict(); + if (!pDict) { + return 0; + } + CFX_ByteString csType = pDict->GetStringBy("S"); + CPDF_Object* pFields = NULL; + if (csType == "Hide") { + pFields = pDict->GetElementValue("T"); + } else { + pFields = pDict->GetArrayBy("Fields"); + } + if (!pFields) + return 0; + if (pFields->IsDictionary()) + return 1; + if (pFields->IsString()) + return 1; + if (CPDF_Array* pArray = pFields->AsArray()) + return pArray->GetCount(); + return 0; +} + +std::vector<CPDF_Object*> CPDF_ActionFields::GetAllFields() const { + std::vector<CPDF_Object*> fields; + if (!m_pAction) + return fields; + + CPDF_Dictionary* pDict = m_pAction->GetDict(); + if (!pDict) + return fields; + + CFX_ByteString csType = pDict->GetStringBy("S"); + CPDF_Object* pFields; + if (csType == "Hide") + pFields = pDict->GetElementValue("T"); + else + pFields = pDict->GetArrayBy("Fields"); + if (!pFields) + return fields; + + if (pFields->IsDictionary() || pFields->IsString()) { + fields.push_back(pFields); + } else if (CPDF_Array* pArray = pFields->AsArray()) { + FX_DWORD iCount = pArray->GetCount(); + for (FX_DWORD i = 0; i < iCount; ++i) { + CPDF_Object* pObj = pArray->GetElementValue(i); + if (pObj) { + fields.push_back(pObj); + } + } + } + return fields; +} + +CPDF_Object* CPDF_ActionFields::GetField(FX_DWORD iIndex) const { + if (!m_pAction) { + return NULL; + } + CPDF_Dictionary* pDict = m_pAction->GetDict(); + if (!pDict) { + return NULL; + } + CFX_ByteString csType = pDict->GetStringBy("S"); + CPDF_Object* pFields = NULL; + if (csType == "Hide") { + pFields = pDict->GetElementValue("T"); + } else { + pFields = pDict->GetArrayBy("Fields"); + } + if (!pFields) { + return NULL; + } + CPDF_Object* pFindObj = NULL; + if (pFields->IsDictionary() || pFields->IsString()) { + if (iIndex == 0) + pFindObj = pFields; + } else if (CPDF_Array* pArray = pFields->AsArray()) { + pFindObj = pArray->GetElementValue(iIndex); + } + return pFindObj; +} + +CFX_WideString CPDF_Action::GetJavaScript() const { + CFX_WideString csJS; + if (!m_pDict) { + return csJS; + } + CPDF_Object* pJS = m_pDict->GetElementValue("JS"); + return pJS ? pJS->GetUnicodeText() : csJS; +} +CPDF_Dictionary* CPDF_Action::GetAnnot() const { + if (!m_pDict) { + return nullptr; + } + CFX_ByteString csType = m_pDict->GetStringBy("S"); + if (csType == "Rendition") { + return m_pDict->GetDictBy("AN"); + } + if (csType == "Movie") { + return m_pDict->GetDictBy("Annotation"); + } + return nullptr; +} +int32_t CPDF_Action::GetOperationType() const { + if (!m_pDict) { + return 0; + } + CFX_ByteString csType = m_pDict->GetStringBy("S"); + if (csType == "Rendition") { + return m_pDict->GetIntegerBy("OP"); + } + if (csType == "Movie") { + CFX_ByteString csOP = m_pDict->GetStringBy("Operation"); + if (csOP == "Play") { + return 0; + } + if (csOP == "Stop") { + return 1; + } + if (csOP == "Pause") { + return 2; + } + if (csOP == "Resume") { + return 3; + } + } + return 0; +} +FX_DWORD CPDF_Action::GetSubActionsCount() const { + if (!m_pDict || !m_pDict->KeyExist("Next")) + return 0; + + CPDF_Object* pNext = m_pDict->GetElementValue("Next"); + if (!pNext) + return 0; + if (pNext->IsDictionary()) + return 1; + if (CPDF_Array* pArray = pNext->AsArray()) + return pArray->GetCount(); + return 0; +} +CPDF_Action CPDF_Action::GetSubAction(FX_DWORD iIndex) const { + if (!m_pDict || !m_pDict->KeyExist("Next")) { + return CPDF_Action(); + } + CPDF_Object* pNext = m_pDict->GetElementValue("Next"); + if (CPDF_Dictionary* pDict = ToDictionary(pNext)) { + if (iIndex == 0) + return CPDF_Action(pDict); + } else if (CPDF_Array* pArray = ToArray(pNext)) { + return CPDF_Action(pArray->GetDictAt(iIndex)); + } + return CPDF_Action(); +} +const FX_CHAR* g_sAATypes[] = {"E", "X", "D", "U", "Fo", "Bl", "PO", "PC", + "PV", "PI", "O", "C", "K", "F", "V", "C", + "WC", "WS", "DS", "WP", "DP", ""}; +FX_BOOL CPDF_AAction::ActionExist(AActionType eType) const { + return m_pDict && m_pDict->KeyExist(g_sAATypes[(int)eType]); +} +CPDF_Action CPDF_AAction::GetAction(AActionType eType) const { + if (!m_pDict) { + return CPDF_Action(); + } + return CPDF_Action(m_pDict->GetDictBy(g_sAATypes[(int)eType])); +} + +CPDF_DocJSActions::CPDF_DocJSActions(CPDF_Document* pDoc) : m_pDocument(pDoc) {} + +int CPDF_DocJSActions::CountJSActions() const { + ASSERT(m_pDocument); + CPDF_NameTree name_tree(m_pDocument, "JavaScript"); + return name_tree.GetCount(); +} +CPDF_Action CPDF_DocJSActions::GetJSAction(int index, + CFX_ByteString& csName) const { + ASSERT(m_pDocument); + CPDF_NameTree name_tree(m_pDocument, "JavaScript"); + CPDF_Object* pAction = name_tree.LookupValue(index, csName); + if (!ToDictionary(pAction)) { + return CPDF_Action(); + } + return CPDF_Action(pAction->GetDict()); +} +CPDF_Action CPDF_DocJSActions::GetJSAction(const CFX_ByteString& csName) const { + ASSERT(m_pDocument); + CPDF_NameTree name_tree(m_pDocument, "JavaScript"); + CPDF_Object* pAction = name_tree.LookupValue(csName); + if (!ToDictionary(pAction)) { + return CPDF_Action(); + } + return CPDF_Action(pAction->GetDict()); +} +int CPDF_DocJSActions::FindJSAction(const CFX_ByteString& csName) const { + ASSERT(m_pDocument); + CPDF_NameTree name_tree(m_pDocument, "JavaScript"); + return name_tree.GetIndex(csName); +} diff --git a/core/fpdfdoc/doc_annot.cpp b/core/fpdfdoc/doc_annot.cpp new file mode 100644 index 0000000000..b17347cce3 --- /dev/null +++ b/core/fpdfdoc/doc_annot.cpp @@ -0,0 +1,350 @@ +// 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/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_reference.h" +#include "core/include/fpdfapi/fpdf_pageobj.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage) + : m_pDocument(pPage->m_pDocument) { + if (!pPage->m_pFormDict) + return; + + CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayBy("Annots"); + if (!pAnnots) + return; + + CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); + CPDF_Dictionary* pAcroForm = pRoot->GetDictBy("AcroForm"); + FX_BOOL bRegenerateAP = + pAcroForm && pAcroForm->GetBooleanBy("NeedAppearances"); + for (FX_DWORD i = 0; i < pAnnots->GetCount(); ++i) { + CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetElementValue(i)); + if (!pDict) + continue; + + FX_DWORD dwObjNum = pDict->GetObjNum(); + if (dwObjNum == 0) { + dwObjNum = m_pDocument->AddIndirectObject(pDict); + CPDF_Reference* pAction = new CPDF_Reference(m_pDocument, dwObjNum); + pAnnots->InsertAt(i, pAction); + pAnnots->RemoveAt(i + 1); + pDict = pAnnots->GetDictAt(i); + } + m_AnnotList.push_back(new CPDF_Annot(pDict, this)); + if (bRegenerateAP && pDict->GetConstStringBy("Subtype") == "Widget" && + CPDF_InterForm::UpdatingAPEnabled()) { + FPDF_GenerateAP(m_pDocument, pDict); + } + } +} + +CPDF_AnnotList::~CPDF_AnnotList() { + for (CPDF_Annot* annot : m_AnnotList) + delete annot; +} + +void CPDF_AnnotList::DisplayPass(CPDF_Page* pPage, + CFX_RenderDevice* pDevice, + CPDF_RenderContext* pContext, + FX_BOOL bPrinting, + CFX_Matrix* pMatrix, + FX_BOOL bWidgetPass, + CPDF_RenderOptions* pOptions, + FX_RECT* clip_rect) { + for (CPDF_Annot* pAnnot : m_AnnotList) { + bool bWidget = pAnnot->GetSubType() == "Widget"; + if ((bWidgetPass && !bWidget) || (!bWidgetPass && bWidget)) + continue; + + FX_DWORD annot_flags = pAnnot->GetFlags(); + if (annot_flags & ANNOTFLAG_HIDDEN) + continue; + + if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) + continue; + + if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) + continue; + + if (pOptions) { + IPDF_OCContext* pOCContext = pOptions->m_pOCContext; + CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict(); + if (pOCContext && pAnnotDict && + !pOCContext->CheckOCGVisible(pAnnotDict->GetDictBy("OC"))) { + continue; + } + } + CFX_FloatRect annot_rect_f; + pAnnot->GetRect(annot_rect_f); + CFX_Matrix matrix = *pMatrix; + if (clip_rect) { + annot_rect_f.Transform(&matrix); + FX_RECT annot_rect = annot_rect_f.GetOutterRect(); + annot_rect.Intersect(*clip_rect); + if (annot_rect.IsEmpty()) { + continue; + } + } + if (pContext) { + pAnnot->DrawInContext(pPage, pContext, &matrix, CPDF_Annot::Normal); + } else if (!pAnnot->DrawAppearance(pPage, pDevice, &matrix, + CPDF_Annot::Normal, pOptions)) { + pAnnot->DrawBorder(pDevice, &matrix, pOptions); + } + } +} + +void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, + CFX_RenderDevice* pDevice, + CPDF_RenderContext* pContext, + FX_BOOL bPrinting, + CFX_Matrix* pUser2Device, + FX_DWORD dwAnnotFlags, + CPDF_RenderOptions* pOptions, + FX_RECT* pClipRect) { + if (dwAnnotFlags & 0x01) { + DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, FALSE, + pOptions, pClipRect); + } + if (dwAnnotFlags & 0x02) { + DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, TRUE, + pOptions, pClipRect); + } +} + +CPDF_Annot::CPDF_Annot(CPDF_Dictionary* pDict, CPDF_AnnotList* pList) + : m_pAnnotDict(pDict), + m_pList(pList), + m_sSubtype(m_pAnnotDict->GetConstStringBy("Subtype")) {} +CPDF_Annot::~CPDF_Annot() { + ClearCachedAP(); +} +void CPDF_Annot::ClearCachedAP() { + for (const auto& pair : m_APMap) { + delete pair.second; + } + m_APMap.clear(); +} +CFX_ByteString CPDF_Annot::GetSubType() const { + return m_sSubtype; +} + +void CPDF_Annot::GetRect(CFX_FloatRect& rect) const { + if (!m_pAnnotDict) { + return; + } + rect = m_pAnnotDict->GetRectBy("Rect"); + rect.Normalize(); +} + +FX_DWORD CPDF_Annot::GetFlags() const { + return m_pAnnotDict->GetIntegerBy("F"); +} + +CPDF_Stream* FPDFDOC_GetAnnotAP(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode mode) { + CPDF_Dictionary* pAP = pAnnotDict->GetDictBy("AP"); + if (!pAP) { + return NULL; + } + const FX_CHAR* ap_entry = "N"; + if (mode == CPDF_Annot::Down) + ap_entry = "D"; + else if (mode == CPDF_Annot::Rollover) + ap_entry = "R"; + if (!pAP->KeyExist(ap_entry)) + ap_entry = "N"; + + CPDF_Object* psub = pAP->GetElementValue(ap_entry); + if (!psub) + return nullptr; + if (CPDF_Stream* pStream = psub->AsStream()) + return pStream; + + if (CPDF_Dictionary* pDict = psub->AsDictionary()) { + CFX_ByteString as = pAnnotDict->GetStringBy("AS"); + if (as.IsEmpty()) { + CFX_ByteString value = pAnnotDict->GetStringBy("V"); + if (value.IsEmpty()) { + CPDF_Dictionary* pDict = pAnnotDict->GetDictBy("Parent"); + value = pDict ? pDict->GetStringBy("V") : CFX_ByteString(); + } + if (value.IsEmpty() || !pDict->KeyExist(value)) + as = "Off"; + else + as = value; + } + return pDict->GetStreamBy(as); + } + return nullptr; +} + +CPDF_Form* CPDF_Annot::GetAPForm(const CPDF_Page* pPage, AppearanceMode mode) { + CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pAnnotDict, mode); + if (!pStream) + return nullptr; + + auto it = m_APMap.find(pStream); + if (it != m_APMap.end()) + return it->second; + + CPDF_Form* pNewForm = + new CPDF_Form(m_pList->GetDocument(), pPage->m_pResources, pStream); + pNewForm->ParseContent(nullptr, nullptr, nullptr, nullptr); + m_APMap[pStream] = pNewForm; + return pNewForm; +} + +static CPDF_Form* FPDFDOC_Annot_GetMatrix(const CPDF_Page* pPage, + CPDF_Annot* pAnnot, + CPDF_Annot::AppearanceMode mode, + const CFX_Matrix* pUser2Device, + CFX_Matrix& matrix) { + CPDF_Form* pForm = pAnnot->GetAPForm(pPage, mode); + if (!pForm) { + return NULL; + } + CFX_FloatRect form_bbox = pForm->m_pFormDict->GetRectBy("BBox"); + CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrixBy("Matrix"); + form_matrix.TransformRect(form_bbox); + CFX_FloatRect arect; + pAnnot->GetRect(arect); + matrix.MatchRect(arect, form_bbox); + matrix.Concat(*pUser2Device); + return pForm; +} +FX_BOOL CPDF_Annot::DrawAppearance(CPDF_Page* pPage, + CFX_RenderDevice* pDevice, + const CFX_Matrix* pUser2Device, + AppearanceMode mode, + const CPDF_RenderOptions* pOptions) { + CFX_Matrix matrix; + CPDF_Form* pForm = + FPDFDOC_Annot_GetMatrix(pPage, this, mode, pUser2Device, matrix); + if (!pForm) { + return FALSE; + } + CPDF_RenderContext context(pPage); + context.AppendLayer(pForm, &matrix); + context.Render(pDevice, pOptions, nullptr); + return TRUE; +} +FX_BOOL CPDF_Annot::DrawInContext(const CPDF_Page* pPage, + CPDF_RenderContext* pContext, + const CFX_Matrix* pUser2Device, + AppearanceMode mode) { + CFX_Matrix matrix; + CPDF_Form* pForm = + FPDFDOC_Annot_GetMatrix(pPage, this, mode, pUser2Device, matrix); + if (!pForm) { + return FALSE; + } + pContext->AppendLayer(pForm, &matrix); + return TRUE; +} +void CPDF_Annot::DrawBorder(CFX_RenderDevice* pDevice, + const CFX_Matrix* pUser2Device, + const CPDF_RenderOptions* pOptions) { + if (GetSubType() == "Popup") { + return; + } + FX_DWORD annot_flags = GetFlags(); + if (annot_flags & ANNOTFLAG_HIDDEN) { + return; + } + bool bPrinting = pDevice->GetDeviceClass() == FXDC_PRINTER || + (pOptions && (pOptions->m_Flags & RENDER_PRINTPREVIEW)); + if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) { + return; + } + if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) { + return; + } + CPDF_Dictionary* pBS = m_pAnnotDict->GetDictBy("BS"); + char style_char; + FX_FLOAT width; + CPDF_Array* pDashArray = NULL; + if (!pBS) { + CPDF_Array* pBorderArray = m_pAnnotDict->GetArrayBy("Border"); + style_char = 'S'; + if (pBorderArray) { + width = pBorderArray->GetNumberAt(2); + if (pBorderArray->GetCount() == 4) { + pDashArray = pBorderArray->GetArrayAt(3); + if (!pDashArray) { + return; + } + int nLen = pDashArray->GetCount(); + int i = 0; + for (; i < nLen; ++i) { + CPDF_Object* pObj = pDashArray->GetElementValue(i); + if (pObj && pObj->GetInteger()) { + break; + } + } + if (i == nLen) { + return; + } + style_char = 'D'; + } + } else { + width = 1; + } + } else { + CFX_ByteString style = pBS->GetStringBy("S"); + pDashArray = pBS->GetArrayBy("D"); + style_char = style[1]; + width = pBS->GetNumberBy("W"); + } + if (width <= 0) { + return; + } + CPDF_Array* pColor = m_pAnnotDict->GetArrayBy("C"); + FX_DWORD argb = 0xff000000; + if (pColor) { + int R = (int32_t)(pColor->GetNumberAt(0) * 255); + int G = (int32_t)(pColor->GetNumberAt(1) * 255); + int B = (int32_t)(pColor->GetNumberAt(2) * 255); + argb = ArgbEncode(0xff, R, G, B); + } + CFX_GraphStateData graph_state; + graph_state.m_LineWidth = width; + if (style_char == 'D') { + if (pDashArray) { + FX_DWORD dash_count = pDashArray->GetCount(); + if (dash_count % 2) { + dash_count++; + } + graph_state.m_DashArray = FX_Alloc(FX_FLOAT, dash_count); + graph_state.m_DashCount = dash_count; + FX_DWORD i; + for (i = 0; i < pDashArray->GetCount(); ++i) { + graph_state.m_DashArray[i] = pDashArray->GetNumberAt(i); + } + if (i < dash_count) { + graph_state.m_DashArray[i] = graph_state.m_DashArray[i - 1]; + } + } else { + graph_state.m_DashArray = FX_Alloc(FX_FLOAT, 2); + graph_state.m_DashCount = 2; + graph_state.m_DashArray[0] = graph_state.m_DashArray[1] = 3 * 1.0f; + } + } + CFX_FloatRect rect; + GetRect(rect); + CFX_PathData path; + width /= 2; + path.AppendRect(rect.left + width, rect.bottom + width, rect.right - width, + rect.top - width); + int fill_type = 0; + if (pOptions && (pOptions->m_Flags & RENDER_NOPATHSMOOTH)) { + fill_type |= FXFILL_NOPATHSMOOTH; + } + pDevice->DrawPath(&path, pUser2Device, &graph_state, argb, argb, fill_type); +} diff --git a/core/fpdfdoc/doc_ap.cpp b/core/fpdfdoc/doc_ap.cpp new file mode 100644 index 0000000000..d2400123d2 --- /dev/null +++ b/core/fpdfdoc/doc_ap.cpp @@ -0,0 +1,936 @@ +// 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/fpdfdoc/doc_utils.h" +#include "core/fpdfdoc/pdf_vt.h" +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_simple_parser.h" +#include "core/include/fpdfdoc/fpdf_ap.h" +#include "core/include/fpdfdoc/fpdf_doc.h" +#include "core/include/fpdfdoc/fpdf_vt.h" + +#define PBS_SOLID 0 +#define PBS_DASH 1 +#define PBS_BEVELED 2 +#define PBS_INSET 3 +#define PBS_UNDERLINED 4 + +FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + if (!pAnnotDict || pAnnotDict->GetConstStringBy("Subtype") != "Widget") { + return FALSE; + } + CFX_ByteString field_type = FPDF_GetFieldAttr(pAnnotDict, "FT")->GetString(); + FX_DWORD flags = FPDF_GetFieldAttr(pAnnotDict, "Ff") + ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() + : 0; + if (field_type == "Tx") { + return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict); + } + if (field_type == "Ch") { + return (flags & (1 << 17)) + ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict) + : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict); + } + if (field_type == "Btn") { + if (!(flags & (1 << 16))) { + if (!pAnnotDict->KeyExist("AS")) { + if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictBy("Parent")) { + if (pParentDict->KeyExist("AS")) { + pAnnotDict->SetAtString("AS", pParentDict->GetStringBy("AS")); + } + } + } + } + } + return FALSE; +} + +class CPVT_FontMap : public IPVT_FontMap { + public: + CPVT_FontMap(CPDF_Document* pDoc, + CPDF_Dictionary* pResDict, + CPDF_Font* pDefFont, + const CFX_ByteString& sDefFontAlias); + ~CPVT_FontMap() override; + + // IPVT_FontMap + CPDF_Font* GetPDFFont(int32_t nFontIndex) override; + CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) override; + + static void GetAnnotSysPDFFont(CPDF_Document* pDoc, + CPDF_Dictionary* pResDict, + CPDF_Font*& pSysFont, + CFX_ByteString& sSysFontAlias); + + private: + CPDF_Document* m_pDocument; + CPDF_Dictionary* m_pResDict; + CPDF_Font* m_pDefFont; + CFX_ByteString m_sDefFontAlias; + CPDF_Font* m_pSysFont; + CFX_ByteString m_sSysFontAlias; +}; + +CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc, + CPDF_Dictionary* pResDict, + CPDF_Font* pDefFont, + const CFX_ByteString& sDefFontAlias) + : m_pDocument(pDoc), + m_pResDict(pResDict), + m_pDefFont(pDefFont), + m_sDefFontAlias(sDefFontAlias), + m_pSysFont(NULL), + m_sSysFontAlias() {} +CPVT_FontMap::~CPVT_FontMap() {} +void CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc, + CPDF_Dictionary* pResDict, + CPDF_Font*& pSysFont, + CFX_ByteString& sSysFontAlias) { + if (pDoc && pResDict) { + CFX_ByteString sFontAlias; + CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictBy("AcroForm"); + if (CPDF_Font* pPDFFont = + AddNativeInterFormFont(pFormDict, pDoc, sSysFontAlias)) { + if (CPDF_Dictionary* pFontList = pResDict->GetDictBy("Font")) { + if (!pFontList->KeyExist(sSysFontAlias)) { + pFontList->SetAtReference(sSysFontAlias, pDoc, + pPDFFont->GetFontDict()); + } + } + pSysFont = pPDFFont; + } + } +} +CPDF_Font* CPVT_FontMap::GetPDFFont(int32_t nFontIndex) { + switch (nFontIndex) { + case 0: + return m_pDefFont; + case 1: + if (!m_pSysFont) { + GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont, + m_sSysFontAlias); + } + return m_pSysFont; + } + return NULL; +} +CFX_ByteString CPVT_FontMap::GetPDFFontAlias(int32_t nFontIndex) { + switch (nFontIndex) { + case 0: + return m_sDefFontAlias; + case 1: + if (!m_pSysFont) { + GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont, + m_sSysFontAlias); + } + return m_sSysFontAlias; + } + return ""; +} +CPVT_Provider::CPVT_Provider(IPVT_FontMap* pFontMap) : m_pFontMap(pFontMap) { + ASSERT(m_pFontMap); +} +CPVT_Provider::~CPVT_Provider() {} +int32_t CPVT_Provider::GetCharWidth(int32_t nFontIndex, + FX_WORD word, + int32_t nWordStyle) { + if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { + FX_DWORD charcode = pPDFFont->CharCodeFromUnicode(word); + if (charcode != CPDF_Font::kInvalidCharCode) { + return pPDFFont->GetCharWidthF(charcode); + } + } + return 0; +} +int32_t CPVT_Provider::GetTypeAscent(int32_t nFontIndex) { + if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { + return pPDFFont->GetTypeAscent(); + } + return 0; +} +int32_t CPVT_Provider::GetTypeDescent(int32_t nFontIndex) { + if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { + return pPDFFont->GetTypeDescent(); + } + return 0; +} +int32_t CPVT_Provider::GetWordFontIndex(FX_WORD word, + int32_t charset, + int32_t nFontIndex) { + if (CPDF_Font* pDefFont = m_pFontMap->GetPDFFont(0)) { + if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) { + return 0; + } + } + if (CPDF_Font* pSysFont = m_pFontMap->GetPDFFont(1)) { + if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) { + return 1; + } + } + return -1; +} +FX_BOOL CPVT_Provider::IsLatinWord(FX_WORD word) { + if ((word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) || + word == 0x2D || word == 0x27) { + return TRUE; + } + return FALSE; +} +int32_t CPVT_Provider::GetDefaultFontIndex() { + return 0; +} + +static CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap, + int32_t nFontIndex, + FX_WORD Word, + FX_WORD SubWord) { + CFX_ByteString sWord; + if (SubWord > 0) { + sWord.Format("%c", SubWord); + return sWord; + } + + if (!pFontMap) + return sWord; + + if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) { + if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 || + pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) { + sWord.Format("%c", Word); + } else { + FX_DWORD dwCharCode = pPDFFont->CharCodeFromUnicode(Word); + if (dwCharCode != CPDF_Font::kInvalidCharCode) { + pPDFFont->AppendChar(sWord, dwCharCode); + } + } + } + return sWord; +} + +static CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) { + if (strWords.GetLength() > 0) { + return PDF_EncodeString(strWords) + " Tj\n"; + } + return ""; +} +static CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap, + int32_t nFontIndex, + FX_FLOAT fFontSize) { + CFX_ByteTextBuf sRet; + if (pFontMap) { + CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); + if (sFontAlias.GetLength() > 0 && fFontSize > 0) { + sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; + } + } + return sRet.GetByteString(); +} +static CPVT_Color ParseColor(const CFX_ByteString& str) { + CPDF_SimpleParser syntax(str); + if (syntax.FindTagParamFromStart("g", 1)) { + return CPVT_Color(CPVT_Color::kGray, FX_atof(syntax.GetWord())); + } + if (syntax.FindTagParamFromStart("rg", 3)) { + FX_FLOAT f1 = FX_atof(syntax.GetWord()); + FX_FLOAT f2 = FX_atof(syntax.GetWord()); + FX_FLOAT f3 = FX_atof(syntax.GetWord()); + return CPVT_Color(CPVT_Color::kRGB, f1, f2, f3); + } + if (syntax.FindTagParamFromStart("k", 4)) { + FX_FLOAT f1 = FX_atof(syntax.GetWord()); + FX_FLOAT f2 = FX_atof(syntax.GetWord()); + FX_FLOAT f3 = FX_atof(syntax.GetWord()); + FX_FLOAT f4 = FX_atof(syntax.GetWord()); + return CPVT_Color(CPVT_Color::kCMYK, f1, f2, f3, f4); + } + return CPVT_Color(CPVT_Color::kTransparent); +} +static CPVT_Color ParseColor(const CPDF_Array& array) { + CPVT_Color rt; + switch (array.GetCount()) { + case 1: + rt = CPVT_Color(CPVT_Color::kGray, array.GetFloatAt(0)); + break; + case 3: + rt = CPVT_Color(CPVT_Color::kRGB, array.GetFloatAt(0), + array.GetFloatAt(1), array.GetFloatAt(2)); + break; + case 4: + rt = CPVT_Color(CPVT_Color::kCMYK, array.GetFloatAt(0), + array.GetFloatAt(1), array.GetFloatAt(2), + array.GetFloatAt(3)); + break; + } + return rt; +} +static FX_BOOL GenerateWidgetAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict, + const int32_t& nWidgetType) { + CPDF_Dictionary* pFormDict = NULL; + if (CPDF_Dictionary* pRootDict = pDoc->GetRoot()) { + pFormDict = pRootDict->GetDictBy("AcroForm"); + } + if (!pFormDict) { + return FALSE; + } + CFX_ByteString DA; + if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA")) { + DA = pDAObj->GetString(); + } + if (DA.IsEmpty()) { + DA = pFormDict->GetStringBy("DA"); + } + if (DA.IsEmpty()) { + return FALSE; + } + CPDF_SimpleParser syntax(DA); + syntax.FindTagParamFromStart("Tf", 2); + CFX_ByteString sFontName = syntax.GetWord(); + sFontName = PDF_NameDecode(sFontName); + if (sFontName.IsEmpty()) { + return FALSE; + } + FX_FLOAT fFontSize = FX_atof(syntax.GetWord()); + CPVT_Color crText = ParseColor(DA); + FX_BOOL bUseFormRes = FALSE; + CPDF_Dictionary* pFontDict = NULL; + CPDF_Dictionary* pDRDict = pAnnotDict->GetDictBy("DR"); + if (!pDRDict) { + pDRDict = pFormDict->GetDictBy("DR"); + bUseFormRes = TRUE; + } + CPDF_Dictionary* pDRFontDict = NULL; + if (pDRDict && (pDRFontDict = pDRDict->GetDictBy("Font"))) { + pFontDict = pDRFontDict->GetDictBy(sFontName.Mid(1)); + if (!pFontDict && !bUseFormRes) { + pDRDict = pFormDict->GetDictBy("DR"); + pDRFontDict = pDRDict->GetDictBy("Font"); + if (pDRFontDict) { + pFontDict = pDRFontDict->GetDictBy(sFontName.Mid(1)); + } + } + } + if (!pDRFontDict) { + return FALSE; + } + if (!pFontDict) { + pFontDict = new CPDF_Dictionary; + pFontDict->SetAtName("Type", "Font"); + pFontDict->SetAtName("Subtype", "Type1"); + pFontDict->SetAtName("BaseFont", "Helvetica"); + pFontDict->SetAtName("Encoding", "WinAnsiEncoding"); + pDoc->AddIndirectObject(pFontDict); + pDRFontDict->SetAtReference(sFontName.Mid(1), pDoc, pFontDict); + } + CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict); + if (!pDefFont) { + return FALSE; + } + CFX_FloatRect rcAnnot = pAnnotDict->GetRectBy("Rect"); + int32_t nRotate = 0; + if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictBy("MK")) { + nRotate = pMKDict->GetIntegerBy("R"); + } + CFX_FloatRect rcBBox; + CFX_Matrix matrix; + switch (nRotate % 360) { + case 0: + rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, + rcAnnot.top - rcAnnot.bottom); + break; + case 90: + matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0); + rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, + rcAnnot.right - rcAnnot.left); + break; + case 180: + matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left, + rcAnnot.top - rcAnnot.bottom); + rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, + rcAnnot.top - rcAnnot.bottom); + break; + case 270: + matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom); + rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, + rcAnnot.right - rcAnnot.left); + break; + } + int32_t nBorderStyle = PBS_SOLID; + FX_FLOAT fBorderWidth = 1; + CPVT_Dash dsBorder(3, 0, 0); + CPVT_Color crLeftTop, crRightBottom; + if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictBy("BS")) { + if (pBSDict->KeyExist("W")) { + fBorderWidth = pBSDict->GetNumberBy("W"); + } + if (CPDF_Array* pArray = pBSDict->GetArrayBy("D")) { + dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1), + pArray->GetIntegerAt(2)); + } + switch (pBSDict->GetStringBy("S").GetAt(0)) { + case 'S': + nBorderStyle = PBS_SOLID; + break; + case 'D': + nBorderStyle = PBS_DASH; + break; + case 'B': + nBorderStyle = PBS_BEVELED; + fBorderWidth *= 2; + crLeftTop = CPVT_Color(CPVT_Color::kGray, 1); + crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5); + break; + case 'I': + nBorderStyle = PBS_INSET; + fBorderWidth *= 2; + crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5); + crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75); + break; + case 'U': + nBorderStyle = PBS_UNDERLINED; + break; + } + } + CPVT_Color crBorder, crBG; + if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictBy("MK")) { + if (CPDF_Array* pArray = pMKDict->GetArrayBy("BC")) { + crBorder = ParseColor(*pArray); + } + if (CPDF_Array* pArray = pMKDict->GetArrayBy("BG")) { + crBG = ParseColor(*pArray); + } + } + CFX_ByteTextBuf sAppStream; + CFX_ByteString sBG = CPVT_GenerateAP::GenerateColorAP(crBG, TRUE); + if (sBG.GetLength() > 0) { + sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " " + << rcBBox.Width() << " " << rcBBox.Height() << " re f\n" + << "Q\n"; + } + CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP( + rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, + dsBorder); + if (sBorderStream.GetLength() > 0) { + sAppStream << "q\n" << sBorderStream << "Q\n"; + } + CFX_FloatRect rcBody = + CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth, + rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth); + rcBody.Normalize(); + CPDF_Dictionary* pAPDict = pAnnotDict->GetDictBy("AP"); + if (!pAPDict) { + pAPDict = new CPDF_Dictionary; + pAnnotDict->SetAt("AP", pAPDict); + } + CPDF_Stream* pNormalStream = pAPDict->GetStreamBy("N"); + if (!pNormalStream) { + pNormalStream = new CPDF_Stream(nullptr, 0, nullptr); + int32_t objnum = pDoc->AddIndirectObject(pNormalStream); + pAnnotDict->GetDictBy("AP")->SetAtReference("N", pDoc, objnum); + } + CPDF_Dictionary* pStreamDict = pNormalStream->GetDict(); + if (pStreamDict) { + pStreamDict->SetAtMatrix("Matrix", matrix); + pStreamDict->SetAtRect("BBox", rcBBox); + CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); + if (pStreamResList) { + CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictBy("Font"); + if (!pStreamResFontList) { + pStreamResFontList = new CPDF_Dictionary; + pStreamResList->SetAt("Font", pStreamResFontList); + } + if (!pStreamResFontList->KeyExist(sFontName)) { + pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); + } + } else { + pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); + pStreamResList = pStreamDict->GetDictBy("Resources"); + } + } + switch (nWidgetType) { + case 0: { + CFX_WideString swValue = + FPDF_GetFieldAttr(pAnnotDict, "V") + ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() + : CFX_WideString(); + int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q") + ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger() + : 0; + FX_DWORD dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff") + ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() + : 0; + FX_DWORD dwMaxLen = + FPDF_GetFieldAttr(pAnnotDict, "MaxLen") + ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger() + : 0; + CPVT_FontMap map(pDoc, + pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, + pDefFont, sFontName.Right(sFontName.GetLength() - 1)); + CPVT_Provider prd(&map); + CPDF_VariableText vt; + vt.SetProvider(&prd); + vt.SetPlateRect(rcBody); + vt.SetAlignment(nAlign); + if (IsFloatZero(fFontSize)) { + vt.SetAutoFontSize(TRUE); + } else { + vt.SetFontSize(fFontSize); + } + FX_BOOL bMultiLine = (dwFlags >> 12) & 1; + if (bMultiLine) { + vt.SetMultiLine(TRUE); + vt.SetAutoReturn(TRUE); + } + FX_WORD subWord = 0; + if ((dwFlags >> 13) & 1) { + subWord = '*'; + vt.SetPasswordChar(subWord); + } + FX_BOOL bCharArray = (dwFlags >> 24) & 1; + if (bCharArray) { + vt.SetCharArray(dwMaxLen); + } else { + vt.SetLimitChar(dwMaxLen); + } + vt.Initialize(); + vt.SetText(swValue.c_str()); + vt.RearrangeAll(); + CFX_FloatRect rcContent = vt.GetContentRect(); + CFX_FloatPoint ptOffset(0.0f, 0.0f); + if (!bMultiLine) { + ptOffset = + CFX_FloatPoint(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f); + } + CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP( + &map, vt.GetIterator(), ptOffset, !bCharArray, subWord); + if (sBody.GetLength() > 0) { + sAppStream << "/Tx BMC\n" + << "q\n"; + if (rcContent.Width() > rcBody.Width() || + rcContent.Height() > rcBody.Height()) { + sAppStream << rcBody.left << " " << rcBody.bottom << " " + << rcBody.Width() << " " << rcBody.Height() + << " re\nW\nn\n"; + } + sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) + << sBody << "ET\n" + << "Q\nEMC\n"; + } + } break; + case 1: { + CFX_WideString swValue = + FPDF_GetFieldAttr(pAnnotDict, "V") + ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() + : CFX_WideString(); + CPVT_FontMap map(pDoc, + pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, + pDefFont, sFontName.Right(sFontName.GetLength() - 1)); + CPVT_Provider prd(&map); + CPDF_VariableText vt; + vt.SetProvider(&prd); + CFX_FloatRect rcButton = rcBody; + rcButton.left = rcButton.right - 13; + rcButton.Normalize(); + CFX_FloatRect rcEdit = rcBody; + rcEdit.right = rcButton.left; + rcEdit.Normalize(); + vt.SetPlateRect(rcEdit); + if (IsFloatZero(fFontSize)) { + vt.SetAutoFontSize(TRUE); + } else { + vt.SetFontSize(fFontSize); + } + vt.Initialize(); + vt.SetText(swValue.c_str()); + vt.RearrangeAll(); + CFX_FloatRect rcContent = vt.GetContentRect(); + CFX_FloatPoint ptOffset = + CFX_FloatPoint(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f); + CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP( + &map, vt.GetIterator(), ptOffset, TRUE, 0); + if (sEdit.GetLength() > 0) { + sAppStream << "/Tx BMC\n" + << "q\n"; + sAppStream << rcEdit.left << " " << rcEdit.bottom << " " + << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n"; + sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) + << sEdit << "ET\n" + << "Q\nEMC\n"; + } + CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP( + CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f, + 220.0f / 255.0f), + TRUE); + if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) { + sAppStream << "q\n" << sButton; + sAppStream << rcButton.left << " " << rcButton.bottom << " " + << rcButton.Width() << " " << rcButton.Height() << " re f\n"; + sAppStream << "Q\n"; + CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP( + rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0), + CPVT_Color(CPVT_Color::kGray, 1), + CPVT_Color(CPVT_Color::kGray, 0.5), PBS_BEVELED, + CPVT_Dash(3, 0, 0)); + if (sButtonBorder.GetLength() > 0) { + sAppStream << "q\n" << sButtonBorder << "Q\n"; + } + CFX_FloatPoint ptCenter = + CFX_FloatPoint((rcButton.left + rcButton.right) / 2, + (rcButton.top + rcButton.bottom) / 2); + if (IsFloatBigger(rcButton.Width(), 6) && + IsFloatBigger(rcButton.Height(), 6)) { + sAppStream << "q\n" + << " 0 g\n"; + sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n"; + sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n"; + sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n"; + sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n"; + sAppStream << sButton << "Q\n"; + } + } + } break; + case 2: { + CPVT_FontMap map(pDoc, + pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, + pDefFont, sFontName.Right(sFontName.GetLength() - 1)); + CPVT_Provider prd(&map); + CPDF_Array* pOpts = FPDF_GetFieldAttr(pAnnotDict, "Opt") + ? FPDF_GetFieldAttr(pAnnotDict, "Opt")->GetArray() + : NULL; + CPDF_Array* pSels = FPDF_GetFieldAttr(pAnnotDict, "I") + ? FPDF_GetFieldAttr(pAnnotDict, "I")->GetArray() + : NULL; + int32_t nTop = FPDF_GetFieldAttr(pAnnotDict, "TI") + ? FPDF_GetFieldAttr(pAnnotDict, "TI")->GetInteger() + : 0; + CFX_ByteTextBuf sBody; + if (pOpts) { + FX_FLOAT fy = rcBody.top; + for (int32_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) { + if (IsFloatSmaller(fy, rcBody.bottom)) { + break; + } + if (CPDF_Object* pOpt = pOpts->GetElementValue(i)) { + CFX_WideString swItem; + if (pOpt->IsString()) + swItem = pOpt->GetUnicodeText(); + else if (CPDF_Array* pArray = pOpt->AsArray()) + swItem = pArray->GetElementValue(1)->GetUnicodeText(); + + FX_BOOL bSelected = FALSE; + if (pSels) { + for (FX_DWORD s = 0, ssz = pSels->GetCount(); s < ssz; s++) { + if (i == pSels->GetIntegerAt(s)) { + bSelected = TRUE; + break; + } + } + } + CPDF_VariableText vt; + vt.SetProvider(&prd); + vt.SetPlateRect( + CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f)); + if (IsFloatZero(fFontSize)) { + vt.SetFontSize(12.0f); + } else { + vt.SetFontSize(fFontSize); + } + vt.Initialize(); + vt.SetText(swItem.c_str()); + vt.RearrangeAll(); + FX_FLOAT fItemHeight = vt.GetContentRect().Height(); + if (bSelected) { + CFX_FloatRect rcItem = CFX_FloatRect( + rcBody.left, fy - fItemHeight, rcBody.right, fy); + sBody << "q\n" << CPVT_GenerateAP::GenerateColorAP( + CPVT_Color(CPVT_Color::kRGB, 0, + 51.0f / 255.0f, 113.0f / 255.0f), + TRUE) + << rcItem.left << " " << rcItem.bottom << " " + << rcItem.Width() << " " << rcItem.Height() << " re f\n" + << "Q\n"; + sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP( + CPVT_Color(CPVT_Color::kGray, 1), TRUE) + << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), + CFX_FloatPoint(0.0f, fy), + TRUE, 0) + << "ET\n"; + } else { + sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) + << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), + CFX_FloatPoint(0.0f, fy), + TRUE, 0) + << "ET\n"; + } + fy -= fItemHeight; + } + } + } + if (sBody.GetSize() > 0) { + sAppStream << "/Tx BMC\n" + << "q\n"; + sAppStream << rcBody.left << " " << rcBody.bottom << " " + << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"; + sAppStream << sBody.GetByteString() << "Q\nEMC\n"; + } + } break; + } + if (pNormalStream) { + pNormalStream->SetData((uint8_t*)sAppStream.GetBuffer(), + sAppStream.GetSize(), FALSE, FALSE); + pStreamDict = pNormalStream->GetDict(); + if (pStreamDict) { + pStreamDict->SetAtMatrix("Matrix", matrix); + pStreamDict->SetAtRect("BBox", rcBBox); + CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); + if (pStreamResList) { + CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictBy("Font"); + if (!pStreamResFontList) { + pStreamResFontList = new CPDF_Dictionary; + pStreamResList->SetAt("Font", pStreamResFontList); + } + if (!pStreamResFontList->KeyExist(sFontName)) { + pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); + } + } else { + pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); + pStreamResList = pStreamDict->GetDictBy("Resources"); + } + } + } + return TRUE; +} +FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict) { + return GenerateWidgetAP(pDoc, pAnnotDict, 0); +} +FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict) { + return GenerateWidgetAP(pDoc, pAnnotDict, 1); +} +FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict) { + return GenerateWidgetAP(pDoc, pAnnotDict, 2); +} +CFX_ByteString CPVT_GenerateAP::GenerateEditAP( + IPVT_FontMap* pFontMap, + IPDF_VariableText_Iterator* pIterator, + const CFX_FloatPoint& ptOffset, + FX_BOOL bContinuous, + FX_WORD SubWord, + const CPVT_WordRange* pVisible) { + CFX_ByteTextBuf sEditStream, sLineStream, sWords; + CFX_FloatPoint ptOld(0.0f, 0.0f), ptNew(0.0f, 0.0f); + int32_t nCurFontIndex = -1; + if (pIterator) { + if (pVisible) { + pIterator->SetAt(pVisible->BeginPos); + } else { + pIterator->SetAt(0); + } + CPVT_WordPlace oldplace; + while (pIterator->NextWord()) { + CPVT_WordPlace place = pIterator->GetAt(); + if (pVisible && place.WordCmp(pVisible->EndPos) > 0) { + break; + } + if (bContinuous) { + if (place.LineCmp(oldplace) != 0) { + if (sWords.GetSize() > 0) { + sLineStream << GetWordRenderString(sWords.GetByteString()); + sEditStream << sLineStream; + sLineStream.Clear(); + 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) { + sLineStream << 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) { + sLineStream << GetWordRenderString(sWords.GetByteString()); + sWords.Clear(); + } + sLineStream << GetFontSetString(pFontMap, word.nFontIndex, + word.fFontSize); + nCurFontIndex = word.nFontIndex; + } + sWords << GetPDFWordString(pFontMap, 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(pFontMap, word.nFontIndex, + word.fFontSize); + nCurFontIndex = word.nFontIndex; + } + sEditStream << GetWordRenderString( + GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord)); + } + } + } + if (sWords.GetSize() > 0) { + sLineStream << GetWordRenderString(sWords.GetByteString()); + sEditStream << sLineStream; + sWords.Clear(); + } + } + return sEditStream.GetByteString(); +} +CFX_ByteString CPVT_GenerateAP::GenerateBorderAP( + const CFX_FloatRect& rect, + FX_FLOAT fWidth, + const CPVT_Color& color, + const CPVT_Color& crLeftTop, + const CPVT_Color& crRightBottom, + int32_t nStyle, + const CPVT_Dash& dash) { + CFX_ByteTextBuf sAppStream; + CFX_ByteString sColor; + FX_FLOAT fLeft = rect.left; + FX_FLOAT fRight = rect.right; + FX_FLOAT fTop = rect.top; + FX_FLOAT fBottom = rect.bottom; + if (fWidth > 0.0f) { + FX_FLOAT fHalfWidth = fWidth / 2.0f; + switch (nStyle) { + default: + case PBS_SOLID: + sColor = GenerateColorAP(color, TRUE); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " + << fTop - fBottom << " re\n"; + sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " " + << fRight - fLeft - fWidth * 2 << " " + << fTop - fBottom - fWidth * 2 << " re\n"; + sAppStream << "f*\n"; + } + break; + case PBS_DASH: + sColor = GenerateColorAP(color, FALSE); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fWidth << " w" + << " [" << dash.nDash << " " << dash.nGap << "] " + << dash.nPhase << " d\n"; + sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 + << " m\n"; + sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 + << " l\n"; + sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 + << " l\n"; + sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 + << " l\n"; + sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 + << " l S\n"; + } + break; + case PBS_BEVELED: + case PBS_INSET: + sColor = GenerateColorAP(crLeftTop, TRUE); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth + << " m\n"; + sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth + << " l\n"; + sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth + << " l\n"; + sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 + << " l\n"; + sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 + << " l\n"; + sAppStream << fLeft + fHalfWidth * 2 << " " + << fBottom + fHalfWidth * 2 << " l f\n"; + } + sColor = GenerateColorAP(crRightBottom, TRUE); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth + << " m\n"; + sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth + << " l\n"; + sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth + << " l\n"; + sAppStream << fLeft + fHalfWidth * 2 << " " + << fBottom + fHalfWidth * 2 << " l\n"; + sAppStream << fRight - fHalfWidth * 2 << " " + << fBottom + fHalfWidth * 2 << " l\n"; + sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 + << " l f\n"; + } + sColor = GenerateColorAP(color, TRUE); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " + << fTop - fBottom << " re\n"; + sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " " + << fRight - fLeft - fHalfWidth * 2 << " " + << fTop - fBottom - fHalfWidth * 2 << " re f*\n"; + } + break; + case PBS_UNDERLINED: + sColor = GenerateColorAP(color, FALSE); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fWidth << " w\n"; + sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n"; + sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n"; + } + break; + } + } + return sAppStream.GetByteString(); +} +CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color, + const FX_BOOL& bFillOrStroke) { + CFX_ByteTextBuf sColorStream; + switch (color.nColorType) { + case CPVT_Color::kRGB: + sColorStream << color.fColor1 << " " << color.fColor2 << " " + << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG") + << "\n"; + break; + case CPVT_Color::kGray: + sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G") + << "\n"; + break; + case CPVT_Color::kCMYK: + sColorStream << color.fColor1 << " " << color.fColor2 << " " + << color.fColor3 << " " << color.fColor4 << " " + << (bFillOrStroke ? "k" : "K") << "\n"; + break; + case CPVT_Color::kTransparent: + break; + } + return sColorStream.GetByteString(); +} diff --git a/core/fpdfdoc/doc_basic.cpp b/core/fpdfdoc/doc_basic.cpp new file mode 100644 index 0000000000..b3a6511734 --- /dev/null +++ b/core/fpdfdoc/doc_basic.cpp @@ -0,0 +1,510 @@ +// 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/fpdfdoc/doc_utils.h" +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +const int nMaxRecursion = 32; +int CPDF_Dest::GetPageIndex(CPDF_Document* pDoc) { + CPDF_Array* pArray = ToArray(m_pObj); + if (!pArray) + return 0; + + CPDF_Object* pPage = pArray->GetElementValue(0); + if (!pPage) + return 0; + if (pPage->IsNumber()) + return pPage->GetInteger(); + if (!pPage->IsDictionary()) + return 0; + return pDoc->GetPageIndex(pPage->GetObjNum()); +} +FX_DWORD CPDF_Dest::GetPageObjNum() { + CPDF_Array* pArray = ToArray(m_pObj); + if (!pArray) + return 0; + + CPDF_Object* pPage = pArray->GetElementValue(0); + if (!pPage) + return 0; + if (pPage->IsNumber()) + return pPage->GetInteger(); + if (pPage->IsDictionary()) + return pPage->GetObjNum(); + return 0; +} +const FX_CHAR* g_sZoomModes[] = {"XYZ", "Fit", "FitH", "FitV", "FitR", + "FitB", "FitBH", "FitBV", ""}; +int CPDF_Dest::GetZoomMode() { + CPDF_Array* pArray = ToArray(m_pObj); + if (!pArray) + return 0; + + CFX_ByteString mode; + CPDF_Object* pObj = pArray->GetElementValue(1); + mode = pObj ? pObj->GetString() : CFX_ByteString(); + int i = 0; + while (g_sZoomModes[i][0] != '\0') { + if (mode == g_sZoomModes[i]) { + return i + 1; + } + i++; + } + return 0; +} +FX_FLOAT CPDF_Dest::GetParam(int index) { + CPDF_Array* pArray = ToArray(m_pObj); + return pArray ? pArray->GetNumberAt(2 + index) : 0; +} +CFX_ByteString CPDF_Dest::GetRemoteName() { + return m_pObj ? m_pObj->GetString() : CFX_ByteString(); +} +CPDF_NameTree::CPDF_NameTree(CPDF_Document* pDoc, + const CFX_ByteStringC& category) { + if (pDoc->GetRoot() && pDoc->GetRoot()->GetDictBy("Names")) + m_pRoot = pDoc->GetRoot()->GetDictBy("Names")->GetDictBy(category); + else + m_pRoot = NULL; +} +static CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode, + const CFX_ByteString& csName, + int& nIndex, + CPDF_Array** ppFind, + int nLevel = 0) { + if (nLevel > nMaxRecursion) { + return NULL; + } + CPDF_Array* pLimits = pNode->GetArrayBy("Limits"); + if (pLimits) { + CFX_ByteString csLeft = pLimits->GetStringAt(0); + CFX_ByteString csRight = pLimits->GetStringAt(1); + if (csLeft.Compare(csRight) > 0) { + CFX_ByteString csTmp = csRight; + csRight = csLeft; + csLeft = csTmp; + } + if (csName.Compare(csLeft) < 0 || csName.Compare(csRight) > 0) { + return NULL; + } + } + CPDF_Array* pNames = pNode->GetArrayBy("Names"); + if (pNames) { + FX_DWORD dwCount = pNames->GetCount() / 2; + for (FX_DWORD i = 0; i < dwCount; i++) { + CFX_ByteString csValue = pNames->GetStringAt(i * 2); + int32_t iCompare = csValue.Compare(csName); + if (iCompare <= 0) { + if (ppFind) { + *ppFind = pNames; + } + if (iCompare < 0) { + continue; + } + } else { + break; + } + nIndex += i; + return pNames->GetElementValue(i * 2 + 1); + } + nIndex += dwCount; + return NULL; + } + CPDF_Array* pKids = pNode->GetArrayBy("Kids"); + if (!pKids) { + return NULL; + } + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pKid = pKids->GetDictAt(i); + if (!pKid) { + continue; + } + CPDF_Object* pFound = + SearchNameNode(pKid, csName, nIndex, ppFind, nLevel + 1); + if (pFound) { + return pFound; + } + } + return NULL; +} +static CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode, + int nIndex, + int& nCurIndex, + CFX_ByteString& csName, + CPDF_Array** ppFind, + int nLevel = 0) { + if (nLevel > nMaxRecursion) { + return NULL; + } + CPDF_Array* pNames = pNode->GetArrayBy("Names"); + if (pNames) { + int nCount = pNames->GetCount() / 2; + if (nIndex >= nCurIndex + nCount) { + nCurIndex += nCount; + return NULL; + } + if (ppFind) { + *ppFind = pNames; + } + csName = pNames->GetStringAt((nIndex - nCurIndex) * 2); + return pNames->GetElementValue((nIndex - nCurIndex) * 2 + 1); + } + CPDF_Array* pKids = pNode->GetArrayBy("Kids"); + if (!pKids) { + return NULL; + } + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pKid = pKids->GetDictAt(i); + if (!pKid) { + continue; + } + CPDF_Object* pFound = + SearchNameNode(pKid, nIndex, nCurIndex, csName, ppFind, nLevel + 1); + if (pFound) { + return pFound; + } + } + return NULL; +} +static int CountNames(CPDF_Dictionary* pNode, int nLevel = 0) { + if (nLevel > nMaxRecursion) { + return 0; + } + CPDF_Array* pNames = pNode->GetArrayBy("Names"); + if (pNames) { + return pNames->GetCount() / 2; + } + CPDF_Array* pKids = pNode->GetArrayBy("Kids"); + if (!pKids) { + return 0; + } + int nCount = 0; + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pKid = pKids->GetDictAt(i); + if (!pKid) { + continue; + } + nCount += CountNames(pKid, nLevel + 1); + } + return nCount; +} +int CPDF_NameTree::GetCount() const { + if (!m_pRoot) { + return 0; + } + return ::CountNames(m_pRoot); +} +int CPDF_NameTree::GetIndex(const CFX_ByteString& csName) const { + if (!m_pRoot) { + return -1; + } + int nIndex = 0; + if (!SearchNameNode(m_pRoot, csName, nIndex, NULL)) { + return -1; + } + return nIndex; +} +CPDF_Object* CPDF_NameTree::LookupValue(int nIndex, + CFX_ByteString& csName) const { + if (!m_pRoot) { + return NULL; + } + int nCurIndex = 0; + return SearchNameNode(m_pRoot, nIndex, nCurIndex, csName, NULL); +} +CPDF_Object* CPDF_NameTree::LookupValue(const CFX_ByteString& csName) const { + if (!m_pRoot) { + return NULL; + } + int nIndex = 0; + return SearchNameNode(m_pRoot, csName, nIndex, NULL); +} +CPDF_Array* CPDF_NameTree::LookupNamedDest(CPDF_Document* pDoc, + const CFX_ByteStringC& sName) { + CPDF_Object* pValue = LookupValue(sName); + if (!pValue) { + CPDF_Dictionary* pDests = pDoc->GetRoot()->GetDictBy("Dests"); + if (!pDests) + return nullptr; + pValue = pDests->GetElementValue(sName); + } + if (!pValue) + return nullptr; + if (CPDF_Array* pArray = pValue->AsArray()) + return pArray; + if (CPDF_Dictionary* pDict = pValue->AsDictionary()) + return pDict->GetArrayBy("D"); + return nullptr; +} + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || \ + _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ +static CFX_WideString ChangeSlashToPlatform(const FX_WCHAR* str) { + CFX_WideString result; + while (*str) { + if (*str == '/') { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + result += ':'; +#else + result += '\\'; +#endif + } else { + result += *str; + } + str++; + } + return result; +} + +static CFX_WideString ChangeSlashToPDF(const FX_WCHAR* str) { + CFX_WideString result; + while (*str) { + if (*str == '\\' || *str == ':') { + result += '/'; + } else { + result += *str; + } + str++; + } + return result; +} +#endif // _FXM_PLATFORM_APPLE_ || _FXM_PLATFORM_WINDOWS_ + +CFX_WideString CPDF_FileSpec::DecodeFileName(const CFX_WideStringC& filepath) { + if (filepath.GetLength() <= 1) + return CFX_WideString(); + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + if (filepath.Left(sizeof("/Mac") - 1) == CFX_WideStringC(L"/Mac")) + return ChangeSlashToPlatform(filepath.GetPtr() + 1); + return ChangeSlashToPlatform(filepath.GetPtr()); +#elif _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + if (filepath.GetAt(0) != '/') + return ChangeSlashToPlatform(filepath.GetPtr()); + if (filepath.GetAt(1) == '/') + return ChangeSlashToPlatform(filepath.GetPtr() + 1); + if (filepath.GetAt(2) == '/') { + CFX_WideString result; + result += filepath.GetAt(1); + result += ':'; + result += ChangeSlashToPlatform(filepath.GetPtr() + 2); + return result; + } + CFX_WideString result; + result += '\\'; + result += ChangeSlashToPlatform(filepath.GetPtr()); + return result; +#else + return filepath; +#endif +} + +bool CPDF_FileSpec::GetFileName(CFX_WideString* csFileName) const { + if (CPDF_Dictionary* pDict = m_pObj->AsDictionary()) { + *csFileName = pDict->GetUnicodeTextBy("UF"); + if (csFileName->IsEmpty()) { + *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("F")); + } + if (pDict->GetStringBy("FS") == "URL") + return true; + if (csFileName->IsEmpty()) { + if (pDict->KeyExist("DOS")) { + *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("DOS")); + } else if (pDict->KeyExist("Mac")) { + *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("Mac")); + } else if (pDict->KeyExist("Unix")) { + *csFileName = CFX_WideString::FromLocal(pDict->GetStringBy("Unix")); + } else { + return false; + } + } + } else if (m_pObj->IsString()) { + *csFileName = CFX_WideString::FromLocal(m_pObj->GetString()); + } else { + return false; + } + *csFileName = DecodeFileName(*csFileName); + return true; +} + +CPDF_FileSpec::CPDF_FileSpec() { + m_pObj = new CPDF_Dictionary; + m_pObj->AsDictionary()->SetAtName("Type", "Filespec"); +} + +CFX_WideString CPDF_FileSpec::EncodeFileName(const CFX_WideStringC& filepath) { + if (filepath.GetLength() <= 1) { + return CFX_WideString(); + } +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + if (filepath.GetAt(1) == ':') { + CFX_WideString result; + result = '/'; + result += filepath.GetAt(0); + if (filepath.GetAt(2) != '\\') { + result += '/'; + } + result += ChangeSlashToPDF(filepath.GetPtr() + 2); + return result; + } + if (filepath.GetAt(0) == '\\' && filepath.GetAt(1) == '\\') { + return ChangeSlashToPDF(filepath.GetPtr() + 1); + } + if (filepath.GetAt(0) == '\\') { + CFX_WideString result; + result = '/'; + result += ChangeSlashToPDF(filepath.GetPtr()); + return result; + } + return ChangeSlashToPDF(filepath.GetPtr()); +#elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + if (filepath.Left(sizeof("Mac") - 1) == FX_WSTRC(L"Mac")) { + CFX_WideString result; + result = '/'; + result += ChangeSlashToPDF(filepath.GetPtr()); + return result; + } + return ChangeSlashToPDF(filepath.GetPtr()); +#else + return filepath; +#endif +} + +void CPDF_FileSpec::SetFileName(const CFX_WideStringC& wsFileName) { + if (!m_pObj) + return; + + CFX_WideString wsStr = EncodeFileName(wsFileName); + if (m_pObj->IsString()) { + m_pObj->SetString(CFX_ByteString::FromUnicode(wsStr)); + } else if (CPDF_Dictionary* pDict = m_pObj->AsDictionary()) { + pDict->SetAtString("F", CFX_ByteString::FromUnicode(wsStr)); + pDict->SetAtString("UF", PDF_EncodeText(wsStr)); + } +} + +static CFX_WideString _MakeRoman(int num) { + const int arabic[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; + const CFX_WideString roman[] = {L"m", L"cm", L"d", L"cd", L"c", + L"xc", L"l", L"xl", L"x", L"ix", + L"v", L"iv", L"i"}; + const int nMaxNum = 1000000; + num %= nMaxNum; + int i = 0; + CFX_WideString wsRomanNumber; + while (num > 0) { + while (num >= arabic[i]) { + num = num - arabic[i]; + wsRomanNumber += roman[i]; + } + i = i + 1; + } + return wsRomanNumber; +} + +static CFX_WideString _MakeLetters(int num) { + if (num == 0) { + return CFX_WideString(); + } + CFX_WideString wsLetters; + const int nMaxCount = 1000; + const int nLetterCount = 26; + num -= 1; + int count = num / nLetterCount + 1; + count %= nMaxCount; + FX_WCHAR ch = L'a' + num % nLetterCount; + for (int i = 0; i < count; i++) { + wsLetters += ch; + } + return wsLetters; +} +static CFX_WideString _GetLabelNumPortion(int num, + const CFX_ByteString& bsStyle) { + CFX_WideString wsNumPortion; + if (bsStyle.IsEmpty()) { + return wsNumPortion; + } + if (bsStyle == "D") { + wsNumPortion.Format(L"%d", num); + } else if (bsStyle == "R") { + wsNumPortion = _MakeRoman(num); + wsNumPortion.MakeUpper(); + } else if (bsStyle == "r") { + wsNumPortion = _MakeRoman(num); + } else if (bsStyle == "A") { + wsNumPortion = _MakeLetters(num); + wsNumPortion.MakeUpper(); + } else if (bsStyle == "a") { + wsNumPortion = _MakeLetters(num); + } + return wsNumPortion; +} +CFX_WideString CPDF_PageLabel::GetLabel(int nPage) const { + CFX_WideString wsLabel; + if (!m_pDocument) { + return wsLabel; + } + CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot(); + if (!pPDFRoot) { + return wsLabel; + } + CPDF_Dictionary* pLabels = pPDFRoot->GetDictBy("PageLabels"); + CPDF_NumberTree numberTree(pLabels); + CPDF_Object* pValue = NULL; + int n = nPage; + while (n >= 0) { + pValue = numberTree.LookupValue(n); + if (pValue) { + break; + } + n--; + } + if (pValue) { + pValue = pValue->GetDirect(); + if (CPDF_Dictionary* pLabel = pValue->AsDictionary()) { + if (pLabel->KeyExist("P")) { + wsLabel += pLabel->GetUnicodeTextBy("P"); + } + CFX_ByteString bsNumberingStyle = pLabel->GetStringBy("S", NULL); + int nLabelNum = nPage - n + pLabel->GetIntegerBy("St", 1); + CFX_WideString wsNumPortion = + _GetLabelNumPortion(nLabelNum, bsNumberingStyle); + wsLabel += wsNumPortion; + return wsLabel; + } + } + wsLabel.Format(L"%d", nPage + 1); + return wsLabel; +} +int32_t CPDF_PageLabel::GetPageByLabel(const CFX_ByteStringC& bsLabel) const { + if (!m_pDocument) { + return -1; + } + CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot(); + if (!pPDFRoot) { + return -1; + } + int nPages = m_pDocument->GetPageCount(); + CFX_ByteString bsLbl; + CFX_ByteString bsOrig = bsLabel; + for (int i = 0; i < nPages; i++) { + bsLbl = PDF_EncodeText(GetLabel(i)); + if (!bsLbl.Compare(bsOrig)) { + return i; + } + } + bsLbl = bsOrig; + int nPage = FXSYS_atoi(bsLbl); + if (nPage > 0 && nPage <= nPages) { + return nPage; + } + return -1; +} +int32_t CPDF_PageLabel::GetPageByLabel(const CFX_WideStringC& wsLabel) const { + CFX_ByteString bsLabel = PDF_EncodeText(wsLabel.GetPtr()); + return GetPageByLabel(bsLabel); +} diff --git a/core/fpdfdoc/doc_basic_unittest.cpp b/core/fpdfdoc/doc_basic_unittest.cpp new file mode 100644 index 0000000000..659643851d --- /dev/null +++ b/core/fpdfdoc/doc_basic_unittest.cpp @@ -0,0 +1,169 @@ +// Copyright 2016 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. + +#include "core/include/fpdfdoc/fpdf_doc.h" + +#include <memory> +#include <vector> + +#include "core/include/fpdfapi/cpdf_name.h" +#include "core/include/fpdfapi/cpdf_string.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" + +namespace { + +using ScopedObj = std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>>; +using ScopedDict = + std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>>; +} + +TEST(doc_basic_filespec, EncodeDecodeFileName) { + std::vector<pdfium::NullTermWstrFuncTestData> test_data = { + // Empty src string. + {L"", L""}, + // only file name. + {L"test.pdf", L"test.pdf"}, +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + // With drive identifier. + {L"r:\\pdfdocs\\spec.pdf", L"/r/pdfdocs/spec.pdf"}, + // Relative path. + {L"My Document\\test.pdf", L"My Document/test.pdf"}, + // Absolute path without drive identifier. + {L"\\pdfdocs\\spec.pdf", L"//pdfdocs/spec.pdf"}, + // Absolute path with double backslashes. + {L"\\\\pdfdocs\\spec.pdf", L"/pdfdocs/spec.pdf"}, +// Network resource name. It is not supported yet. +// {L"pclib/eng:\\pdfdocs\\spec.pdf", L"/pclib/eng/pdfdocs/spec.pdf"}, +#elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + // Absolute path with colon separator. + {L"Mac HD:PDFDocs:spec.pdf", L"/Mac HD/PDFDocs/spec.pdf"}, + // Relative path with colon separator. + {L"PDFDocs:spec.pdf", L"PDFDocs/spec.pdf"}, +#else + // Relative path. + {L"./docs/test.pdf", L"./docs/test.pdf"}, + // Relative path with parent dir. + {L"../test_docs/test.pdf", L"../test_docs/test.pdf"}, + // Absolute path. + {L"/usr/local/home/test.pdf", L"/usr/local/home/test.pdf"}, +#endif + }; + for (const auto& data : test_data) { + CFX_WideString encoded_str = CPDF_FileSpec::EncodeFileName(data.input); + EXPECT_TRUE(encoded_str.Equal(data.expected)); + // DecodeFileName is the reverse procedure of EncodeFileName. + CFX_WideString decoded_str = CPDF_FileSpec::DecodeFileName(data.expected); + EXPECT_TRUE(decoded_str.Equal(data.input)); + } +} + +TEST(doc_basic_filespec, GetFileName) { + { + // String object. + pdfium::NullTermWstrFuncTestData test_data = { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + L"/C/docs/test.pdf", + L"C:\\docs\\test.pdf" +#elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + L"/Mac HD/docs/test.pdf", + L"Mac HD:docs:test.pdf" +#else + L"/docs/test.pdf", + L"/docs/test.pdf" +#endif + }; + ScopedObj str_obj(new CPDF_String(test_data.input)); + CPDF_FileSpec file_spec(str_obj.get()); + CFX_WideString file_name; + EXPECT_TRUE(file_spec.GetFileName(&file_name)); + EXPECT_TRUE(file_name.Equal(test_data.expected)); + } + { + // Dictionary object. + pdfium::NullTermWstrFuncTestData test_data[5] = { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + {L"/C/docs/test.pdf", L"C:\\docs\\test.pdf"}, + {L"/D/docs/test.pdf", L"D:\\docs\\test.pdf"}, + {L"/E/docs/test.pdf", L"E:\\docs\\test.pdf"}, + {L"/F/docs/test.pdf", L"F:\\docs\\test.pdf"}, + {L"/G/docs/test.pdf", L"G:\\docs\\test.pdf"}, +#elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + {L"/Mac HD/docs1/test.pdf", L"Mac HD:docs1:test.pdf"}, + {L"/Mac HD/docs2/test.pdf", L"Mac HD:docs2:test.pdf"}, + {L"/Mac HD/docs3/test.pdf", L"Mac HD:docs3:test.pdf"}, + {L"/Mac HD/docs4/test.pdf", L"Mac HD:docs4:test.pdf"}, + {L"/Mac HD/docs5/test.pdf", L"Mac HD:docs5:test.pdf"}, +#else + {L"/docs/a/test.pdf", L"/docs/a/test.pdf"}, + {L"/docs/b/test.pdf", L"/docs/b/test.pdf"}, + {L"/docs/c/test.pdf", L"/docs/c/test.pdf"}, + {L"/docs/d/test.pdf", L"/docs/d/test.pdf"}, + {L"/docs/e/test.pdf", L"/docs/e/test.pdf"}, +#endif + }; + // Keyword fields in reverse order of precedence to retrieve the file name. + const char* const keywords[5] = {"Unix", "Mac", "DOS", "F", "UF"}; + ScopedDict dict_obj(new CPDF_Dictionary); + CPDF_FileSpec file_spec(dict_obj.get()); + CFX_WideString file_name; + for (int i = 0; i < 5; ++i) { + dict_obj->SetAt(keywords[i], new CPDF_String(test_data[i].input)); + EXPECT_TRUE(file_spec.GetFileName(&file_name)); + EXPECT_TRUE(file_name.Equal(test_data[i].expected)); + } + + // With all the former fields and 'FS' field suggests 'URL' type. + dict_obj->SetAtString("FS", "URL"); + EXPECT_TRUE(file_spec.GetFileName(&file_name)); + // Url string is not decoded. + EXPECT_TRUE(file_name.Equal(test_data[4].input)); + } + { + // Invalid object. + ScopedObj name_obj(new CPDF_Name("test.pdf")); + CPDF_FileSpec file_spec(name_obj.get()); + CFX_WideString file_name; + EXPECT_FALSE(file_spec.GetFileName(&file_name)); + } +} + +TEST(doc_basic_filespec, SetFileName) { + pdfium::NullTermWstrFuncTestData test_data = { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + L"C:\\docs\\test.pdf", + L"/C/docs/test.pdf" +#elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + L"Mac HD:docs:test.pdf", + L"/Mac HD/docs/test.pdf" +#else + L"/docs/test.pdf", + L"/docs/test.pdf" +#endif + }; + // String object. + ScopedObj str_obj(new CPDF_String(L"babababa")); + CPDF_FileSpec file_spec1(str_obj.get()); + file_spec1.SetFileName(test_data.input); + // Check internal object value. + CFX_ByteString str = CFX_ByteString::FromUnicode(test_data.expected); + EXPECT_TRUE(str == str_obj->GetString()); + // Check we can get the file name back. + CFX_WideString file_name; + EXPECT_TRUE(file_spec1.GetFileName(&file_name)); + EXPECT_TRUE(file_name.Equal(test_data.input)); + + // Dictionary object. + ScopedDict dict_obj(new CPDF_Dictionary); + CPDF_FileSpec file_spec2(dict_obj.get()); + file_spec2.SetFileName(test_data.input); + // Check internal object value. + file_name = dict_obj->GetUnicodeTextBy("F"); + EXPECT_TRUE(file_name.Equal(test_data.expected)); + file_name = dict_obj->GetUnicodeTextBy("UF"); + EXPECT_TRUE(file_name.Equal(test_data.expected)); + // Check we can get the file name back. + EXPECT_TRUE(file_spec2.GetFileName(&file_name)); + EXPECT_TRUE(file_name.Equal(test_data.input)); +} diff --git a/core/fpdfdoc/doc_bookmark.cpp b/core/fpdfdoc/doc_bookmark.cpp new file mode 100644 index 0000000000..c338e5d48c --- /dev/null +++ b/core/fpdfdoc/doc_bookmark.cpp @@ -0,0 +1,95 @@ +// 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 <memory> +#include <vector> + +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_string.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +CPDF_Bookmark CPDF_BookmarkTree::GetFirstChild( + const CPDF_Bookmark& parent) const { + if (!parent.GetDict()) { + CPDF_Dictionary* pRoot = m_pDocument->GetRoot()->GetDictBy("Outlines"); + if (!pRoot) + return CPDF_Bookmark(); + return CPDF_Bookmark(pRoot->GetDictBy("First")); + } + return CPDF_Bookmark(parent.GetDict()->GetDictBy("First")); +} + +CPDF_Bookmark CPDF_BookmarkTree::GetNextSibling( + const CPDF_Bookmark& bookmark) const { + if (!bookmark.GetDict()) + return CPDF_Bookmark(); + + CPDF_Dictionary* pNext = bookmark.GetDict()->GetDictBy("Next"); + return pNext == bookmark.GetDict() ? CPDF_Bookmark() : CPDF_Bookmark(pNext); +} + +FX_DWORD CPDF_Bookmark::GetColorRef() const { + if (!m_pDict) { + return 0; + } + CPDF_Array* pColor = m_pDict->GetArrayBy("C"); + if (!pColor) { + return FXSYS_RGB(0, 0, 0); + } + int r = FXSYS_round(pColor->GetNumberAt(0) * 255); + int g = FXSYS_round(pColor->GetNumberAt(1) * 255); + int b = FXSYS_round(pColor->GetNumberAt(2) * 255); + return FXSYS_RGB(r, g, b); +} +FX_DWORD CPDF_Bookmark::GetFontStyle() const { + if (!m_pDict) { + return 0; + } + return m_pDict->GetIntegerBy("F"); +} +CFX_WideString CPDF_Bookmark::GetTitle() const { + if (!m_pDict) { + return CFX_WideString(); + } + CPDF_String* pString = ToString(m_pDict->GetElementValue("Title")); + if (!pString) + return CFX_WideString(); + + CFX_WideString title = pString->GetUnicodeText(); + int len = title.GetLength(); + if (!len) { + return CFX_WideString(); + } + std::unique_ptr<FX_WCHAR[]> buf(new FX_WCHAR[len]); + for (int i = 0; i < len; i++) { + FX_WCHAR w = title[i]; + buf[i] = w > 0x20 ? w : 0x20; + } + return CFX_WideString(buf.get(), len); +} +CPDF_Dest CPDF_Bookmark::GetDest(CPDF_Document* pDocument) const { + if (!m_pDict) + return CPDF_Dest(); + + CPDF_Object* pDest = m_pDict->GetElementValue("Dest"); + if (!pDest) + return CPDF_Dest(); + if (pDest->IsString() || pDest->IsName()) { + CPDF_NameTree name_tree(pDocument, "Dests"); + CFX_ByteStringC name = pDest->GetString(); + return CPDF_Dest(name_tree.LookupNamedDest(pDocument, name)); + } + if (CPDF_Array* pArray = pDest->AsArray()) + return CPDF_Dest(pArray); + return CPDF_Dest(); +} +CPDF_Action CPDF_Bookmark::GetAction() const { + if (!m_pDict) { + return CPDF_Action(); + } + return CPDF_Action(m_pDict->GetDictBy("A")); +} diff --git a/core/fpdfdoc/doc_form.cpp b/core/fpdfdoc/doc_form.cpp new file mode 100644 index 0000000000..c205588335 --- /dev/null +++ b/core/fpdfdoc/doc_form.cpp @@ -0,0 +1,1207 @@ +// 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 <vector> + +#include "core/fpdfdoc/doc_utils.h" +#include "core/include/fpdfapi/cfdf_document.h" +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_string.h" +#include "core/include/fpdfdoc/fpdf_doc.h" +#include "third_party/base/stl_util.h" + +namespace { + +const int nMaxRecursion = 32; + +const struct SupportFieldEncoding { + const FX_CHAR* m_name; + FX_WORD m_codePage; +} g_fieldEncoding[] = { + {"BigFive", 950}, + {"GBK", 936}, + {"Shift-JIS", 932}, + {"UHC", 949}, +}; + +CFX_WideString FPDFDOC_FDF_GetFieldValue(const CPDF_Dictionary& pFieldDict, + const CFX_ByteString& bsEncoding) { + const CFX_ByteString csBValue = pFieldDict.GetStringBy("V"); + for (const auto& encoding : g_fieldEncoding) { + if (bsEncoding == encoding.m_name) + return CFX_WideString::FromCodePage(csBValue, encoding.m_codePage); + } + CFX_ByteString csTemp = csBValue.Left(2); + if (csTemp == "\xFF\xFE" || csTemp == "\xFE\xFF") + return PDF_DecodeText(csBValue); + return CFX_WideString::FromLocal(csBValue); +} + +} // namespace + +class CFieldNameExtractor { + public: + explicit CFieldNameExtractor(const CFX_WideString& full_name) { + m_pStart = full_name.c_str(); + m_pEnd = m_pStart + full_name.GetLength(); + m_pCur = m_pStart; + } + void GetNext(const FX_WCHAR*& pSubName, FX_STRSIZE& size) { + pSubName = m_pCur; + while (m_pCur < m_pEnd && m_pCur[0] != L'.') { + m_pCur++; + } + size = (FX_STRSIZE)(m_pCur - pSubName); + if (m_pCur < m_pEnd && m_pCur[0] == L'.') { + m_pCur++; + } + } + + protected: + const FX_WCHAR* m_pStart; + const FX_WCHAR* m_pEnd; + const FX_WCHAR* m_pCur; +}; +class CFieldTree { + public: + struct _Node { + _Node* parent; + CFX_ArrayTemplate<_Node*> children; + CFX_WideString short_name; + CPDF_FormField* field_ptr; + int CountFields(int nLevel = 0) { + if (nLevel > nMaxRecursion) { + return 0; + } + if (field_ptr) { + return 1; + } + int count = 0; + for (int i = 0; i < children.GetSize(); i++) { + count += children.GetAt(i)->CountFields(nLevel + 1); + } + return count; + } + CPDF_FormField* GetField(int* fields_to_go) { + if (field_ptr) { + if (*fields_to_go == 0) { + return field_ptr; + } + --*fields_to_go; + return NULL; + } + for (int i = 0; i < children.GetSize(); i++) { + if (CPDF_FormField* pField = children.GetAt(i)->GetField(fields_to_go)) + return pField; + } + return NULL; + } + CPDF_FormField* GetField(int index) { + int fields_to_go = index; + return GetField(&fields_to_go); + } + }; + CFieldTree(); + ~CFieldTree(); + void SetField(const CFX_WideString& full_name, CPDF_FormField* field_ptr); + CPDF_FormField* GetField(const CFX_WideString& full_name); + CPDF_FormField* RemoveField(const CFX_WideString& full_name); + void RemoveAll(); + _Node* FindNode(const CFX_WideString& full_name); + _Node* AddChild(_Node* pParent, + const CFX_WideString& short_name, + CPDF_FormField* field_ptr); + void RemoveNode(_Node* pNode, int nLevel = 0); + _Node* _Lookup(_Node* pParent, const CFX_WideString& short_name); + _Node m_Root; +}; +CFieldTree::CFieldTree() { + m_Root.parent = NULL; + m_Root.field_ptr = NULL; +} +CFieldTree::~CFieldTree() { + RemoveAll(); +} +CFieldTree::_Node* CFieldTree::AddChild(_Node* pParent, + const CFX_WideString& short_name, + CPDF_FormField* field_ptr) { + if (!pParent) { + return NULL; + } + _Node* pNode = new _Node; + pNode->parent = pParent; + pNode->short_name = short_name; + pNode->field_ptr = field_ptr; + pParent->children.Add(pNode); + return pNode; +} +void CFieldTree::RemoveNode(_Node* pNode, int nLevel) { + if (!pNode) { + return; + } + if (nLevel <= nMaxRecursion) { + for (int i = 0; i < pNode->children.GetSize(); i++) { + RemoveNode(pNode->children[i], nLevel + 1); + } + } + delete pNode; +} +CFieldTree::_Node* CFieldTree::_Lookup(_Node* pParent, + const CFX_WideString& short_name) { + if (!pParent) { + return NULL; + } + for (int i = 0; i < pParent->children.GetSize(); i++) { + _Node* pNode = pParent->children[i]; + if (pNode->short_name.GetLength() == short_name.GetLength() && + FXSYS_memcmp(pNode->short_name.c_str(), short_name.c_str(), + short_name.GetLength() * sizeof(FX_WCHAR)) == 0) { + return pNode; + } + } + return NULL; +} +void CFieldTree::RemoveAll() { + for (int i = 0; i < m_Root.children.GetSize(); i++) { + RemoveNode(m_Root.children[i]); + } +} +void CFieldTree::SetField(const CFX_WideString& full_name, + CPDF_FormField* field_ptr) { + if (full_name == L"") { + return; + } + CFieldNameExtractor name_extractor(full_name); + const FX_WCHAR* pName; + FX_STRSIZE nLength; + name_extractor.GetNext(pName, nLength); + _Node *pNode = &m_Root, *pLast = NULL; + while (nLength > 0) { + pLast = pNode; + CFX_WideString name = CFX_WideString(pName, nLength); + pNode = _Lookup(pLast, name); + if (!pNode) { + pNode = AddChild(pLast, name, NULL); + } + name_extractor.GetNext(pName, nLength); + } + if (pNode != &m_Root) { + pNode->field_ptr = field_ptr; + } +} +CPDF_FormField* CFieldTree::GetField(const CFX_WideString& full_name) { + if (full_name == L"") { + return NULL; + } + CFieldNameExtractor name_extractor(full_name); + const FX_WCHAR* pName; + FX_STRSIZE nLength; + name_extractor.GetNext(pName, nLength); + _Node *pNode = &m_Root, *pLast = NULL; + while (nLength > 0 && pNode) { + pLast = pNode; + CFX_WideString name = CFX_WideString(pName, nLength); + pNode = _Lookup(pLast, name); + name_extractor.GetNext(pName, nLength); + } + return pNode ? pNode->field_ptr : NULL; +} +CPDF_FormField* CFieldTree::RemoveField(const CFX_WideString& full_name) { + if (full_name == L"") { + return NULL; + } + CFieldNameExtractor name_extractor(full_name); + const FX_WCHAR* pName; + FX_STRSIZE nLength; + name_extractor.GetNext(pName, nLength); + _Node *pNode = &m_Root, *pLast = NULL; + while (nLength > 0 && pNode) { + pLast = pNode; + CFX_WideString name = CFX_WideString(pName, nLength); + pNode = _Lookup(pLast, name); + name_extractor.GetNext(pName, nLength); + } + if (pNode && pNode != &m_Root) { + for (int i = 0; i < pLast->children.GetSize(); i++) { + if (pNode == pLast->children[i]) { + pLast->children.RemoveAt(i); + break; + } + } + CPDF_FormField* pField = pNode->field_ptr; + RemoveNode(pNode); + return pField; + } + return NULL; +} +CFieldTree::_Node* CFieldTree::FindNode(const CFX_WideString& full_name) { + if (full_name == L"") { + return NULL; + } + CFieldNameExtractor name_extractor(full_name); + const FX_WCHAR* pName; + FX_STRSIZE nLength; + name_extractor.GetNext(pName, nLength); + _Node *pNode = &m_Root, *pLast = NULL; + while (nLength > 0 && pNode) { + pLast = pNode; + CFX_WideString name = CFX_WideString(pName, nLength); + pNode = _Lookup(pLast, name); + name_extractor.GetNext(pName, nLength); + } + return pNode; +} +CPDF_InterForm::CPDF_InterForm(CPDF_Document* pDocument, FX_BOOL bGenerateAP) + : CFX_PrivateData(), + m_pDocument(pDocument), + m_bGenerateAP(bGenerateAP), + m_pFormDict(nullptr), + m_pFieldTree(new CFieldTree), + m_pFormNotify(nullptr), + m_bUpdated(FALSE) { + CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); + if (!pRoot) + return; + + m_pFormDict = pRoot->GetDictBy("AcroForm"); + if (!m_pFormDict) + return; + + CPDF_Array* pFields = m_pFormDict->GetArrayBy("Fields"); + if (!pFields) + return; + + int count = pFields->GetCount(); + for (int i = 0; i < count; i++) { + LoadField(pFields->GetDictAt(i)); + } +} + +CPDF_InterForm::~CPDF_InterForm() { + for (auto it : m_ControlMap) + delete it.second; + + int nCount = m_pFieldTree->m_Root.CountFields(); + for (int i = 0; i < nCount; ++i) { + delete m_pFieldTree->m_Root.GetField(i); + } +} + +FX_BOOL CPDF_InterForm::m_bUpdateAP = TRUE; +FX_BOOL CPDF_InterForm::UpdatingAPEnabled() { + return m_bUpdateAP; +} +void CPDF_InterForm::EnableUpdateAP(FX_BOOL bUpdateAP) { + m_bUpdateAP = bUpdateAP; +} +CFX_ByteString CPDF_InterForm::GenerateNewResourceName( + const CPDF_Dictionary* pResDict, + const FX_CHAR* csType, + int iMinLen, + const FX_CHAR* csPrefix) { + CFX_ByteString csStr = csPrefix; + CFX_ByteString csBType = csType; + if (csStr.IsEmpty()) { + if (csBType == "ExtGState") { + csStr = "GS"; + } else if (csBType == "ColorSpace") { + csStr = "CS"; + } else if (csBType == "Font") { + csStr = "ZiTi"; + } else { + csStr = "Res"; + } + } + CFX_ByteString csTmp = csStr; + int iCount = csStr.GetLength(); + int m = 0; + if (iMinLen > 0) { + csTmp = ""; + while (m < iMinLen && m < iCount) { + csTmp += csStr[m++]; + } + while (m < iMinLen) { + csTmp += '0' + m % 10; + m++; + } + } else { + m = iCount; + } + if (!pResDict) { + return csTmp; + } + CPDF_Dictionary* pDict = pResDict->GetDictBy(csType); + if (!pDict) { + return csTmp; + } + int num = 0; + CFX_ByteString bsNum; + while (TRUE) { + if (!pDict->KeyExist(csTmp + bsNum)) { + return csTmp + bsNum; + } + if (m < iCount) { + csTmp += csStr[m++]; + } else { + bsNum.Format("%d", num++); + } + m++; + } + return csTmp; +} +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ +typedef struct PDF_FONTDATA_ { + FX_BOOL bFind; + LOGFONTA lf; +} PDF_FONTDATA, FAR* LPDF_FONTDATA; +static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe, + NEWTEXTMETRICEX* lpntme, + DWORD FontType, + LPARAM lParam) { + if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@')) { + return 1; + } + LPDF_FONTDATA pData = (LPDF_FONTDATA)lParam; + memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA)); + pData->bFind = TRUE; + return 0; +} +static FX_BOOL RetrieveSpecificFont(LOGFONTA& lf) { + PDF_FONTDATA fd; + memset(&fd, 0, sizeof(PDF_FONTDATA)); + HDC hDC = ::GetDC(NULL); + EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd, + 0); + ::ReleaseDC(NULL, hDC); + if (fd.bFind) { + memcpy(&lf, &fd.lf, sizeof(LOGFONTA)); + } + return fd.bFind; +} +static FX_BOOL RetrieveSpecificFont(uint8_t charSet, + uint8_t pitchAndFamily, + LPCSTR pcsFontName, + LOGFONTA& lf) { + memset(&lf, 0, sizeof(LOGFONTA)); + lf.lfCharSet = charSet; + lf.lfPitchAndFamily = pitchAndFamily; + if (pcsFontName) { + // TODO(dsinclair): Should this be strncpy? + strcpy(lf.lfFaceName, pcsFontName); + } + return RetrieveSpecificFont(lf); +} +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + +CPDF_Font* CPDF_InterForm::AddStandardFont(CPDF_Document* pDocument, + CFX_ByteString csFontName) { + if (!pDocument || csFontName.IsEmpty()) + return nullptr; + + if (csFontName == "ZapfDingbats") + return pDocument->AddStandardFont(csFontName.c_str(), nullptr); + + CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI); + return pDocument->AddStandardFont(csFontName.c_str(), &encoding); +} + +CFX_ByteString CPDF_InterForm::GetNativeFont(uint8_t charSet, void* pLogFont) { + CFX_ByteString csFontName; +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + LOGFONTA lf; + FX_BOOL bRet; + if (charSet == ANSI_CHARSET) { + csFontName = "Helvetica"; + return csFontName; + } + bRet = FALSE; + if (charSet == SHIFTJIS_CHARSET) { + bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, + "MS Mincho", lf); + } else if (charSet == GB2312_CHARSET) { + bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "SimSun", + lf); + } else if (charSet == CHINESEBIG5_CHARSET) { + bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "MingLiU", + lf); + } + if (!bRet) { + bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, + "Arial Unicode MS", lf); + } + if (!bRet) { + bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, + "Microsoft Sans Serif", lf); + } + if (!bRet) { + bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, NULL, lf); + } + if (bRet) { + if (pLogFont) { + memcpy(pLogFont, &lf, sizeof(LOGFONTA)); + } + csFontName = lf.lfFaceName; + return csFontName; + } +#endif + return csFontName; +} +CFX_ByteString CPDF_InterForm::GetNativeFont(void* pLogFont) { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + uint8_t charSet = GetNativeCharSet(); + return GetNativeFont(charSet, pLogFont); +#else + return CFX_ByteString(); +#endif +} +uint8_t CPDF_InterForm::GetNativeCharSet() { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + uint8_t charSet = ANSI_CHARSET; + UINT iCodePage = ::GetACP(); + switch (iCodePage) { + case 932: + charSet = SHIFTJIS_CHARSET; + break; + case 936: + charSet = GB2312_CHARSET; + break; + case 950: + charSet = CHINESEBIG5_CHARSET; + break; + case 1252: + charSet = ANSI_CHARSET; + break; + case 874: + charSet = THAI_CHARSET; + break; + case 949: + charSet = HANGUL_CHARSET; + break; + case 1200: + charSet = ANSI_CHARSET; + break; + case 1250: + charSet = EASTEUROPE_CHARSET; + break; + case 1251: + charSet = RUSSIAN_CHARSET; + break; + case 1253: + charSet = GREEK_CHARSET; + break; + case 1254: + charSet = TURKISH_CHARSET; + break; + case 1255: + charSet = HEBREW_CHARSET; + break; + case 1256: + charSet = ARABIC_CHARSET; + break; + case 1257: + charSet = BALTIC_CHARSET; + break; + case 1258: + charSet = VIETNAMESE_CHARSET; + break; + case 1361: + charSet = JOHAB_CHARSET; + break; + } + return charSet; +#else + return 0; +#endif +} + +CPDF_Font* CPDF_InterForm::AddNativeFont(uint8_t charSet, + CPDF_Document* pDocument) { + if (!pDocument) + return nullptr; + +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + LOGFONTA lf; + CFX_ByteString csFontName = GetNativeFont(charSet, &lf); + if (!csFontName.IsEmpty()) { + if (csFontName == "Helvetica") + return AddStandardFont(pDocument, csFontName); + return pDocument->AddWindowsFont(&lf, FALSE, TRUE); + } +#endif + return nullptr; +} + +CPDF_Font* CPDF_InterForm::AddNativeFont(CPDF_Document* pDocument) { + return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr; +} + +FX_BOOL CPDF_InterForm::ValidateFieldName( + CFX_WideString& csNewFieldName, + int iType, + const CPDF_FormField* pExcludedField, + const CPDF_FormControl* pExcludedControl) { + if (csNewFieldName.IsEmpty()) { + return FALSE; + } + int iPos = 0; + int iLength = csNewFieldName.GetLength(); + CFX_WideString csSub; + while (TRUE) { + while (iPos < iLength && + (csNewFieldName[iPos] == L'.' || csNewFieldName[iPos] == L' ')) { + iPos++; + } + if (iPos < iLength && !csSub.IsEmpty()) { + csSub += L'.'; + } + while (iPos < iLength && csNewFieldName[iPos] != L'.') { + csSub += csNewFieldName[iPos++]; + } + for (int i = csSub.GetLength() - 1; i > -1; i--) { + if (csSub[i] == L' ' || csSub[i] == L'.') { + csSub.SetAt(i, L'\0'); + } else { + break; + } + } + FX_DWORD dwCount = m_pFieldTree->m_Root.CountFields(); + for (FX_DWORD m = 0; m < dwCount; m++) { + CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(m); + if (!pField) { + continue; + } + if (pField == pExcludedField) { + if (pExcludedControl) { + if (pField->CountControls() < 2) { + continue; + } + } else { + continue; + } + } + CFX_WideString csFullName = pField->GetFullName(); + int iRet = CompareFieldName(csSub, csFullName); + if (iRet == 1) { + if (pField->GetFieldType() != iType) { + return FALSE; + } + } else if (iRet == 2 && csSub == csNewFieldName) { + if (csFullName[iPos] == L'.') { + return FALSE; + } + } else if (iRet == 3 && csSub == csNewFieldName) { + if (csNewFieldName[csFullName.GetLength()] == L'.') { + return FALSE; + } + } + } + if (iPos >= iLength) { + break; + } + } + if (csSub.IsEmpty()) { + return FALSE; + } + csNewFieldName = csSub; + return TRUE; +} +FX_BOOL CPDF_InterForm::ValidateFieldName(CFX_WideString& csNewFieldName, + int iType) { + return ValidateFieldName(csNewFieldName, iType, NULL, NULL); +} +FX_BOOL CPDF_InterForm::ValidateFieldName(const CPDF_FormField* pField, + CFX_WideString& csNewFieldName) { + return pField && !csNewFieldName.IsEmpty() && + ValidateFieldName(csNewFieldName, + ((CPDF_FormField*)pField)->GetFieldType(), pField, + NULL); +} +FX_BOOL CPDF_InterForm::ValidateFieldName(const CPDF_FormControl* pControl, + CFX_WideString& csNewFieldName) { + if (!pControl || csNewFieldName.IsEmpty()) { + return FALSE; + } + CPDF_FormField* pField = ((CPDF_FormControl*)pControl)->GetField(); + return ValidateFieldName(csNewFieldName, pField->GetFieldType(), pField, + pControl); +} +int CPDF_InterForm::CompareFieldName(const CFX_ByteString& name1, + const CFX_ByteString& name2) { + const FX_CHAR* ptr1 = name1; + const FX_CHAR* ptr2 = name2; + if (name1.GetLength() == name2.GetLength()) { + return name1 == name2 ? 1 : 0; + } + int i = 0; + while (ptr1[i] == ptr2[i]) { + i++; + } + if (i == name1.GetLength()) { + return 2; + } + if (i == name2.GetLength()) { + return 3; + } + return 0; +} +int CPDF_InterForm::CompareFieldName(const CFX_WideString& name1, + const CFX_WideString& name2) { + const FX_WCHAR* ptr1 = name1.c_str(); + const FX_WCHAR* ptr2 = name2.c_str(); + if (name1.GetLength() == name2.GetLength()) { + return name1 == name2 ? 1 : 0; + } + int i = 0; + while (ptr1[i] == ptr2[i]) { + i++; + } + if (i == name1.GetLength()) { + return 2; + } + if (i == name2.GetLength()) { + return 3; + } + return 0; +} +FX_DWORD CPDF_InterForm::CountFields(const CFX_WideString& csFieldName) { + if (csFieldName.IsEmpty()) { + return (FX_DWORD)m_pFieldTree->m_Root.CountFields(); + } + CFieldTree::_Node* pNode = m_pFieldTree->FindNode(csFieldName); + return pNode ? pNode->CountFields() : 0; +} +CPDF_FormField* CPDF_InterForm::GetField(FX_DWORD index, + const CFX_WideString& csFieldName) { + if (csFieldName == L"") { + return m_pFieldTree->m_Root.GetField(index); + } + CFieldTree::_Node* pNode = m_pFieldTree->FindNode(csFieldName); + return pNode ? pNode->GetField(index) : nullptr; +} + +CPDF_FormField* CPDF_InterForm::GetFieldByDict( + CPDF_Dictionary* pFieldDict) const { + if (!pFieldDict) { + return NULL; + } + CFX_WideString csWName = GetFullName(pFieldDict); + return m_pFieldTree->GetField(csWName); +} + +CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage, + FX_FLOAT pdf_x, + FX_FLOAT pdf_y, + int* z_order) const { + CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayBy("Annots"); + if (!pAnnotList) + return nullptr; + + for (FX_DWORD i = pAnnotList->GetCount(); i > 0; --i) { + FX_DWORD annot_index = i - 1; + CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index); + if (!pAnnot) + continue; + + const auto it = m_ControlMap.find(pAnnot); + if (it == m_ControlMap.end()) + continue; + + CPDF_FormControl* pControl = it->second; + CFX_FloatRect rect = pControl->GetRect(); + if (!rect.Contains(pdf_x, pdf_y)) + continue; + + if (z_order) + *z_order = annot_index; + return pControl; + } + return nullptr; +} + +CPDF_FormControl* CPDF_InterForm::GetControlByDict( + const CPDF_Dictionary* pWidgetDict) const { + const auto it = m_ControlMap.find(pWidgetDict); + return it != m_ControlMap.end() ? it->second : nullptr; +} + +FX_BOOL CPDF_InterForm::NeedConstructAP() { + return m_pFormDict && m_pFormDict->GetBooleanBy("NeedAppearances"); +} +void CPDF_InterForm::NeedConstructAP(FX_BOOL bNeedAP) { + if (!m_pFormDict) { + InitInterFormDict(m_pFormDict, m_pDocument); + } + m_pFormDict->SetAtBoolean("NeedAppearances", bNeedAP); + m_bGenerateAP = bNeedAP; +} +int CPDF_InterForm::CountFieldsInCalculationOrder() { + if (!m_pFormDict) { + return 0; + } + CPDF_Array* pArray = m_pFormDict->GetArrayBy("CO"); + return pArray ? pArray->GetCount() : 0; +} +CPDF_FormField* CPDF_InterForm::GetFieldInCalculationOrder(int index) { + if (!m_pFormDict || index < 0) { + return NULL; + } + CPDF_Array* pArray = m_pFormDict->GetArrayBy("CO"); + if (!pArray) { + return NULL; + } + if (CPDF_Dictionary* pElement = + ToDictionary(pArray->GetElementValue(index))) { + return GetFieldByDict(pElement); + } + return NULL; +} +int CPDF_InterForm::FindFieldInCalculationOrder(const CPDF_FormField* pField) { + if (!m_pFormDict || !pField) { + return -1; + } + CPDF_Array* pArray = m_pFormDict->GetArrayBy("CO"); + if (!pArray) { + return -1; + } + for (FX_DWORD i = 0; i < pArray->GetCount(); i++) { + CPDF_Object* pElement = pArray->GetElementValue(i); + if (pElement == pField->m_pDict) { + return i; + } + } + return -1; +} +FX_DWORD CPDF_InterForm::CountFormFonts() { + return CountInterFormFonts(m_pFormDict); +} +CPDF_Font* CPDF_InterForm::GetFormFont(FX_DWORD index, + CFX_ByteString& csNameTag) { + return GetInterFormFont(m_pFormDict, m_pDocument, index, csNameTag); +} +CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csNameTag) { + return GetInterFormFont(m_pFormDict, m_pDocument, csNameTag); +} +CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csFontName, + CFX_ByteString& csNameTag) { + return GetInterFormFont(m_pFormDict, m_pDocument, csFontName, csNameTag); +} +CPDF_Font* CPDF_InterForm::GetNativeFormFont(uint8_t charSet, + CFX_ByteString& csNameTag) { + return GetNativeInterFormFont(m_pFormDict, m_pDocument, charSet, csNameTag); +} +CPDF_Font* CPDF_InterForm::GetNativeFormFont(CFX_ByteString& csNameTag) { + return GetNativeInterFormFont(m_pFormDict, m_pDocument, csNameTag); +} +FX_BOOL CPDF_InterForm::FindFormFont(const CPDF_Font* pFont, + CFX_ByteString& csNameTag) { + return FindInterFormFont(m_pFormDict, pFont, csNameTag); +} +FX_BOOL CPDF_InterForm::FindFormFont(CFX_ByteString csFontName, + CPDF_Font*& pFont, + CFX_ByteString& csNameTag) { + return FindInterFormFont(m_pFormDict, m_pDocument, csFontName, pFont, + csNameTag); +} +void CPDF_InterForm::AddFormFont(const CPDF_Font* pFont, + CFX_ByteString& csNameTag) { + AddInterFormFont(m_pFormDict, m_pDocument, pFont, csNameTag); + m_bUpdated = TRUE; +} +CPDF_Font* CPDF_InterForm::AddNativeFormFont(uint8_t charSet, + CFX_ByteString& csNameTag) { + m_bUpdated = TRUE; + return AddNativeInterFormFont(m_pFormDict, m_pDocument, charSet, csNameTag); +} +CPDF_Font* CPDF_InterForm::AddNativeFormFont(CFX_ByteString& csNameTag) { + m_bUpdated = TRUE; + return AddNativeInterFormFont(m_pFormDict, m_pDocument, csNameTag); +} +void CPDF_InterForm::RemoveFormFont(const CPDF_Font* pFont) { + m_bUpdated = TRUE; + RemoveInterFormFont(m_pFormDict, pFont); +} +void CPDF_InterForm::RemoveFormFont(CFX_ByteString csNameTag) { + m_bUpdated = TRUE; + RemoveInterFormFont(m_pFormDict, csNameTag); +} + +CPDF_DefaultAppearance CPDF_InterForm::GetDefaultAppearance() { + if (!m_pFormDict) + return CPDF_DefaultAppearance(); + return CPDF_DefaultAppearance(m_pFormDict->GetStringBy("DA")); +} + +CPDF_Font* CPDF_InterForm::GetDefaultFormFont() { + return GetDefaultInterFormFont(m_pFormDict, m_pDocument); +} +int CPDF_InterForm::GetFormAlignment() { + return m_pFormDict ? m_pFormDict->GetIntegerBy("Q", 0) : 0; +} + +bool CPDF_InterForm::ResetForm(const std::vector<CPDF_FormField*>& fields, + bool bIncludeOrExclude, + bool bNotify) { + if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0) + return false; + + int nCount = m_pFieldTree->m_Root.CountFields(); + for (int i = 0; i < nCount; ++i) { + CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i); + if (!pField) + continue; + + if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) + pField->ResetField(bNotify); + } + if (bNotify && m_pFormNotify) + m_pFormNotify->AfterFormReset(this); + return true; +} + +bool CPDF_InterForm::ResetForm(bool bNotify) { + if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0) + return false; + + int nCount = m_pFieldTree->m_Root.CountFields(); + for (int i = 0; i < nCount; ++i) { + CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i); + if (!pField) + continue; + + pField->ResetField(bNotify); + } + if (bNotify && m_pFormNotify) + m_pFormNotify->AfterFormReset(this); + return true; +} + +void CPDF_InterForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) { + if (nLevel > nMaxRecursion) { + return; + } + if (!pFieldDict) { + return; + } + FX_DWORD dwParentObjNum = pFieldDict->GetObjNum(); + CPDF_Array* pKids = pFieldDict->GetArrayBy("Kids"); + if (!pKids) { + AddTerminalField(pFieldDict); + return; + } + CPDF_Dictionary* pFirstKid = pKids->GetDictAt(0); + if (!pFirstKid) { + return; + } + if (pFirstKid->KeyExist("T") || pFirstKid->KeyExist("Kids")) { + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pChildDict = pKids->GetDictAt(i); + if (pChildDict) { + if (pChildDict->GetObjNum() != dwParentObjNum) { + LoadField(pChildDict, nLevel + 1); + } + } + } + } else { + AddTerminalField(pFieldDict); + } +} +FX_BOOL CPDF_InterForm::HasXFAForm() const { + return m_pFormDict && m_pFormDict->GetArrayBy("XFA"); +} +void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) { + CPDF_Dictionary* pPageDict = pPage->m_pFormDict; + if (!pPageDict) { + return; + } + CPDF_Array* pAnnots = pPageDict->GetArrayBy("Annots"); + if (!pAnnots) { + return; + } + int iAnnotCount = pAnnots->GetCount(); + for (int i = 0; i < iAnnotCount; i++) { + CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i); + if (pAnnot && pAnnot->GetStringBy("Subtype") == "Widget") { + LoadField(pAnnot); + } + } +} +CPDF_FormField* CPDF_InterForm::AddTerminalField(CPDF_Dictionary* pFieldDict) { + if (!pFieldDict->KeyExist("T")) { + return NULL; + } + CPDF_Dictionary* pDict = pFieldDict; + CFX_WideString csWName = GetFullName(pFieldDict); + if (csWName.IsEmpty()) { + return NULL; + } + CPDF_FormField* pField = NULL; + pField = m_pFieldTree->GetField(csWName); + if (!pField) { + CPDF_Dictionary* pParent = pFieldDict; + if (!pFieldDict->KeyExist("T") && + pFieldDict->GetStringBy("Subtype") == "Widget") { + pParent = pFieldDict->GetDictBy("Parent"); + if (!pParent) { + pParent = pFieldDict; + } + } + if (pParent && pParent != pFieldDict && !pParent->KeyExist("FT")) { + if (pFieldDict->KeyExist("FT")) { + CPDF_Object* pFTValue = pFieldDict->GetElementValue("FT"); + if (pFTValue) { + pParent->SetAt("FT", pFTValue->Clone()); + } + } + if (pFieldDict->KeyExist("Ff")) { + CPDF_Object* pFfValue = pFieldDict->GetElementValue("Ff"); + if (pFfValue) { + pParent->SetAt("Ff", pFfValue->Clone()); + } + } + } + pField = new CPDF_FormField(this, pParent); + CPDF_Object* pTObj = pDict->GetElement("T"); + if (ToReference(pTObj)) { + CPDF_Object* pClone = pTObj->Clone(TRUE); + if (pClone) + pDict->SetAt("T", pClone); + else + pDict->SetAtName("T", ""); + } + m_pFieldTree->SetField(csWName, pField); + } + CPDF_Array* pKids = pFieldDict->GetArrayBy("Kids"); + if (!pKids) { + if (pFieldDict->GetStringBy("Subtype") == "Widget") { + AddControl(pField, pFieldDict); + } + } else { + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pKid = pKids->GetDictAt(i); + if (!pKid) { + continue; + } + if (pKid->GetStringBy("Subtype") != "Widget") { + continue; + } + AddControl(pField, pKid); + } + } + return pField; +} +CPDF_FormControl* CPDF_InterForm::AddControl(const CPDF_FormField* pField, + CPDF_Dictionary* pWidgetDict) { + const auto it = m_ControlMap.find(pWidgetDict); + if (it != m_ControlMap.end()) + return it->second; + + CPDF_FormControl* pControl = + new CPDF_FormControl((CPDF_FormField*)pField, pWidgetDict); + m_ControlMap[pWidgetDict] = pControl; + ((CPDF_FormField*)pField)->m_ControlList.Add(pControl); + return pControl; +} + +CPDF_FormField* CPDF_InterForm::CheckRequiredFields( + const std::vector<CPDF_FormField*>* fields, + bool bIncludeOrExclude) const { + int nCount = m_pFieldTree->m_Root.CountFields(); + for (int i = 0; i < nCount; ++i) { + CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i); + if (!pField) + continue; + + int32_t iType = pField->GetType(); + if (iType == CPDF_FormField::PushButton || + iType == CPDF_FormField::CheckBox || iType == CPDF_FormField::ListBox) { + continue; + } + FX_DWORD dwFlags = pField->GetFieldFlags(); + // TODO(thestig): Look up these magic numbers and add constants for them. + if (dwFlags & 0x04) + continue; + + bool bFind = true; + if (fields) + bFind = pdfium::ContainsValue(*fields, pField); + if (bIncludeOrExclude == bFind) { + CPDF_Dictionary* pFieldDict = pField->m_pDict; + if ((dwFlags & 0x02) != 0 && pFieldDict->GetStringBy("V").IsEmpty()) { + return pField; + } + } + } + return nullptr; +} + +CFDF_Document* CPDF_InterForm::ExportToFDF(const CFX_WideStringC& pdf_path, + bool bSimpleFileSpec) const { + std::vector<CPDF_FormField*> fields; + int nCount = m_pFieldTree->m_Root.CountFields(); + for (int i = 0; i < nCount; ++i) + fields.push_back(m_pFieldTree->m_Root.GetField(i)); + return ExportToFDF(pdf_path, fields, true, bSimpleFileSpec); +} + +CFDF_Document* CPDF_InterForm::ExportToFDF( + const CFX_WideStringC& pdf_path, + const std::vector<CPDF_FormField*>& fields, + bool bIncludeOrExclude, + bool bSimpleFileSpec) const { + CFDF_Document* pDoc = CFDF_Document::CreateNewDoc(); + if (!pDoc) { + return NULL; + } + CPDF_Dictionary* pMainDict = pDoc->GetRoot()->GetDictBy("FDF"); + if (!pdf_path.IsEmpty()) { + if (bSimpleFileSpec) { + CFX_WideString wsFilePath = CPDF_FileSpec::EncodeFileName(pdf_path); + pMainDict->SetAtString("F", CFX_ByteString::FromUnicode(wsFilePath)); + pMainDict->SetAtString("UF", PDF_EncodeText(wsFilePath)); + } else { + CPDF_FileSpec filespec; + filespec.SetFileName(pdf_path); + pMainDict->SetAt("F", filespec.GetObj()); + } + } + CPDF_Array* pFields = new CPDF_Array; + pMainDict->SetAt("Fields", pFields); + int nCount = m_pFieldTree->m_Root.CountFields(); + for (int i = 0; i < nCount; i++) { + CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i); + if (!pField || pField->GetType() == CPDF_FormField::PushButton) { + continue; + } + FX_DWORD dwFlags = pField->GetFieldFlags(); + if (dwFlags & 0x04) + continue; + + if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) { + if ((dwFlags & 0x02) != 0 && pField->m_pDict->GetStringBy("V").IsEmpty()) + continue; + + CFX_WideString fullname = GetFullName(pField->GetFieldDict()); + CPDF_Dictionary* pFieldDict = new CPDF_Dictionary; + pFieldDict->SetAt("T", new CPDF_String(fullname)); + if (pField->GetType() == CPDF_FormField::CheckBox || + pField->GetType() == CPDF_FormField::RadioButton) { + CFX_WideString csExport = pField->GetCheckValue(FALSE); + CFX_ByteString csBExport = PDF_EncodeText(csExport); + CPDF_Object* pOpt = FPDF_GetFieldAttr(pField->m_pDict, "Opt"); + if (pOpt) + pFieldDict->SetAtString("V", csBExport); + else + pFieldDict->SetAtName("V", csBExport); + } else { + CPDF_Object* pV = FPDF_GetFieldAttr(pField->m_pDict, "V"); + if (pV) + pFieldDict->SetAt("V", pV->Clone(TRUE)); + } + pFields->Add(pFieldDict); + } + } + return pDoc; +} + +void CPDF_InterForm::FDF_ImportField(CPDF_Dictionary* pFieldDict, + const CFX_WideString& parent_name, + FX_BOOL bNotify, + int nLevel) { + CFX_WideString name; + if (!parent_name.IsEmpty()) { + name = parent_name + L"."; + } + name += pFieldDict->GetUnicodeTextBy("T"); + CPDF_Array* pKids = pFieldDict->GetArrayBy("Kids"); + if (pKids) { + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pKid = pKids->GetDictAt(i); + if (!pKid) { + continue; + } + if (nLevel <= nMaxRecursion) { + FDF_ImportField(pKid, name, bNotify, nLevel + 1); + } + } + return; + } + if (!pFieldDict->KeyExist("V")) { + return; + } + CPDF_FormField* pField = m_pFieldTree->GetField(name); + if (!pField) { + return; + } + CFX_WideString csWValue = + FPDFDOC_FDF_GetFieldValue(*pFieldDict, m_bsEncoding); + int iType = pField->GetFieldType(); + if (bNotify && m_pFormNotify) { + int iRet = 0; + if (iType == FIELDTYPE_LISTBOX) { + iRet = m_pFormNotify->BeforeSelectionChange(pField, csWValue); + } else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD) { + iRet = m_pFormNotify->BeforeValueChange(pField, csWValue); + } + if (iRet < 0) { + return; + } + } + pField->SetValue(csWValue); + CPDF_FormField::Type eType = pField->GetType(); + if ((eType == CPDF_FormField::ListBox || eType == CPDF_FormField::ComboBox) && + pFieldDict->KeyExist("Opt")) { + pField->m_pDict->SetAt("Opt", + pFieldDict->GetElementValue("Opt")->Clone(TRUE)); + } + if (bNotify && m_pFormNotify) { + if (iType == FIELDTYPE_CHECKBOX || iType == FIELDTYPE_RADIOBUTTON) { + m_pFormNotify->AfterCheckedStatusChange(pField); + } else if (iType == FIELDTYPE_LISTBOX) { + m_pFormNotify->AfterSelectionChange(pField); + } else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD) { + m_pFormNotify->AfterValueChange(pField); + } + } + if (CPDF_InterForm::m_bUpdateAP) { + pField->UpdateAP(NULL); + } +} +FX_BOOL CPDF_InterForm::ImportFromFDF(const CFDF_Document* pFDF, + FX_BOOL bNotify) { + if (!pFDF) { + return FALSE; + } + CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDictBy("FDF"); + if (!pMainDict) { + return FALSE; + } + CPDF_Array* pFields = pMainDict->GetArrayBy("Fields"); + if (!pFields) { + return FALSE; + } + m_bsEncoding = pMainDict->GetStringBy("Encoding"); + if (bNotify && m_pFormNotify) { + int iRet = m_pFormNotify->BeforeFormImportData(this); + if (iRet < 0) { + return FALSE; + } + } + for (FX_DWORD i = 0; i < pFields->GetCount(); i++) { + CPDF_Dictionary* pField = pFields->GetDictAt(i); + if (!pField) { + continue; + } + FDF_ImportField(pField, L"", bNotify); + } + if (bNotify && m_pFormNotify) { + m_pFormNotify->AfterFormImportData(this); + } + return TRUE; +} +void CPDF_InterForm::SetFormNotify(const CPDF_FormNotify* pNotify) { + m_pFormNotify = (CPDF_FormNotify*)pNotify; +} diff --git a/core/fpdfdoc/doc_formcontrol.cpp b/core/fpdfdoc/doc_formcontrol.cpp new file mode 100644 index 0000000000..15ff7b5e64 --- /dev/null +++ b/core/fpdfdoc/doc_formcontrol.cpp @@ -0,0 +1,432 @@ +// 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 <algorithm> + +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField, + CPDF_Dictionary* pWidgetDict) { + m_pField = pField; + m_pWidgetDict = pWidgetDict; + m_pForm = m_pField->m_pForm; +} +CFX_FloatRect CPDF_FormControl::GetRect() const { + return m_pWidgetDict->GetRectBy("Rect"); +} +CFX_ByteString CPDF_FormControl::GetOnStateName() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn; + CPDF_Dictionary* pAP = m_pWidgetDict->GetDictBy("AP"); + if (!pAP) { + return csOn; + } + CPDF_Dictionary* pN = pAP->GetDictBy("N"); + if (!pN) { + return csOn; + } + for (const auto& it : *pN) { + if (it.first != "Off") { + return it.first; + } + } + return CFX_ByteString(); +} +void CPDF_FormControl::SetOnStateName(const CFX_ByteString& csOn) { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csValue = csOn; + if (csValue.IsEmpty()) { + csValue = "Yes"; + } + if (csValue == "Off") { + csValue = "Yes"; + } + CFX_ByteString csAS = m_pWidgetDict->GetStringBy("AS", "Off"); + if (csAS != "Off") { + m_pWidgetDict->SetAtName("AS", csValue); + } + CPDF_Dictionary* pAP = m_pWidgetDict->GetDictBy("AP"); + if (!pAP) { + return; + } + for (const auto& it : *pAP) { + CPDF_Object* pObj1 = it.second; + if (!pObj1) { + continue; + } + CPDF_Object* pObjDirect1 = pObj1->GetDirect(); + CPDF_Dictionary* pSubDict = pObjDirect1->AsDictionary(); + if (!pSubDict) + continue; + + auto subdict_it = pSubDict->begin(); + while (subdict_it != pSubDict->end()) { + const CFX_ByteString& csKey2 = subdict_it->first; + CPDF_Object* pObj2 = subdict_it->second; + ++subdict_it; + if (!pObj2) { + continue; + } + if (csKey2 != "Off") { + pSubDict->ReplaceKey(csKey2, csValue); + break; + } + } + } +} +CFX_ByteString CPDF_FormControl::GetCheckedAPState() { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + if (GetType() == CPDF_FormField::RadioButton || + GetType() == CPDF_FormField::CheckBox) { + if (ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) { + int iIndex = m_pField->GetControlIndex(this); + csOn.Format("%d", iIndex); + } + } + if (csOn.IsEmpty()) + csOn = "Yes"; + return csOn; +} +CFX_WideString CPDF_FormControl::GetExportValue() { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + if (GetType() == CPDF_FormField::RadioButton || + GetType() == CPDF_FormField::CheckBox) { + if (CPDF_Array* pArray = + ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) { + int iIndex = m_pField->GetControlIndex(this); + csOn = pArray->GetStringAt(iIndex); + } + } + if (csOn.IsEmpty()) { + csOn = "Yes"; + } + CFX_WideString csWOn = PDF_DecodeText(csOn); + return csWOn; +} + +bool CPDF_FormControl::IsChecked() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + CFX_ByteString csAS = m_pWidgetDict->GetStringBy("AS"); + return csAS == csOn; +} + +bool CPDF_FormControl::IsDefaultChecked() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CPDF_Object* pDV = FPDF_GetFieldAttr(m_pField->m_pDict, "DV"); + if (!pDV) { + return FALSE; + } + CFX_ByteString csDV = pDV->GetString(); + CFX_ByteString csOn = GetOnStateName(); + return (csDV == csOn); +} + +void CPDF_FormControl::CheckControl(FX_BOOL bChecked) { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + CFX_ByteString csOldAS = m_pWidgetDict->GetStringBy("AS", "Off"); + CFX_ByteString csAS = "Off"; + if (bChecked) { + csAS = csOn; + } + if (csOldAS == csAS) { + return; + } + m_pWidgetDict->SetAtName("AS", csAS); + m_pForm->m_bUpdated = TRUE; +} +CPDF_Stream* FPDFDOC_GetAnnotAP(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode mode); +void CPDF_FormControl::DrawControl(CFX_RenderDevice* pDevice, + CFX_Matrix* pMatrix, + CPDF_Page* pPage, + CPDF_Annot::AppearanceMode mode, + const CPDF_RenderOptions* pOptions) { + if (m_pWidgetDict->GetIntegerBy("F") & ANNOTFLAG_HIDDEN) { + return; + } + CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pWidgetDict, mode); + if (!pStream) { + return; + } + CFX_FloatRect form_bbox = pStream->GetDict()->GetRectBy("BBox"); + CFX_Matrix form_matrix = pStream->GetDict()->GetMatrixBy("Matrix"); + form_matrix.TransformRect(form_bbox); + CFX_FloatRect arect = m_pWidgetDict->GetRectBy("Rect"); + CFX_Matrix matrix; + matrix.MatchRect(arect, form_bbox); + matrix.Concat(*pMatrix); + CPDF_Form form(m_pField->m_pForm->m_pDocument, + m_pField->m_pForm->m_pFormDict->GetDictBy("DR"), pStream); + form.ParseContent(NULL, NULL, NULL, NULL); + CPDF_RenderContext context(pPage); + context.AppendLayer(&form, &matrix); + context.Render(pDevice, pOptions, nullptr); +} +static const FX_CHAR* const g_sHighlightingMode[] = { + // Must match order of HiglightingMode enum. + "N", "I", "O", "P", "T", nullptr}; +CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() { + if (!m_pWidgetDict) { + return Invert; + } + CFX_ByteString csH = m_pWidgetDict->GetStringBy("H", "I"); + for (int i = 0; g_sHighlightingMode[i]; ++i) { + if (csH.Equal(g_sHighlightingMode[i])) + return static_cast<HighlightingMode>(i); + } + return Invert; +} + +CPDF_ApSettings CPDF_FormControl::GetMK() const { + return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDictBy("MK") + : nullptr); +} + +bool CPDF_FormControl::HasMKEntry(CFX_ByteString csEntry) const { + return GetMK().HasMKEntry(csEntry); +} + +int CPDF_FormControl::GetRotation() { + return GetMK().GetRotation(); +} + +FX_ARGB CPDF_FormControl::GetColor(int& iColorType, CFX_ByteString csEntry) { + return GetMK().GetColor(iColorType, csEntry); +} + +FX_FLOAT CPDF_FormControl::GetOriginalColor(int index, CFX_ByteString csEntry) { + return GetMK().GetOriginalColor(index, csEntry); +} + +void CPDF_FormControl::GetOriginalColor(int& iColorType, + FX_FLOAT fc[4], + CFX_ByteString csEntry) { + GetMK().GetOriginalColor(iColorType, fc, csEntry); +} +CFX_WideString CPDF_FormControl::GetCaption(CFX_ByteString csEntry) { + return GetMK().GetCaption(csEntry); +} + +CPDF_Stream* CPDF_FormControl::GetIcon(CFX_ByteString csEntry) { + return GetMK().GetIcon(csEntry); +} + +CPDF_IconFit CPDF_FormControl::GetIconFit() { + return GetMK().GetIconFit(); +} + +int CPDF_FormControl::GetTextPosition() { + return GetMK().GetTextPosition(); +} + +CPDF_Action CPDF_FormControl::GetAction() { + if (!m_pWidgetDict) { + return CPDF_Action(); + } + if (m_pWidgetDict->KeyExist("A")) { + return CPDF_Action(m_pWidgetDict->GetDictBy("A")); + } + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "A"); + if (!pObj) { + return CPDF_Action(); + } + return CPDF_Action(pObj->GetDict()); +} + +CPDF_AAction CPDF_FormControl::GetAdditionalAction() { + if (!m_pWidgetDict) + return CPDF_AAction(); + + if (m_pWidgetDict->KeyExist("AA")) + return CPDF_AAction(m_pWidgetDict->GetDictBy("AA")); + return m_pField->GetAdditionalAction(); +} + +CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() { + if (!m_pWidgetDict) + return CPDF_DefaultAppearance(); + + if (m_pWidgetDict->KeyExist("DA")) + return CPDF_DefaultAppearance(m_pWidgetDict->GetStringBy("DA")); + + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "DA"); + if (pObj) + return CPDF_DefaultAppearance(pObj->GetString()); + return m_pField->m_pForm->GetDefaultAppearance(); +} + +CPDF_Font* CPDF_FormControl::GetDefaultControlFont() { + CPDF_DefaultAppearance cDA = GetDefaultAppearance(); + CFX_ByteString csFontNameTag; + FX_FLOAT fFontSize; + cDA.GetFont(csFontNameTag, fFontSize); + if (csFontNameTag.IsEmpty()) + return nullptr; + + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pWidgetDict, "DR"); + if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { + CPDF_Dictionary* pFonts = pDict->GetDictBy("Font"); + if (pFonts) { + CPDF_Dictionary* pElement = pFonts->GetDictBy(csFontNameTag); + if (pElement) { + CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement); + if (pFont) { + return pFont; + } + } + } + } + if (CPDF_Font* pFormFont = m_pField->m_pForm->GetFormFont(csFontNameTag)) + return pFormFont; + + CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictBy("P"); + pObj = FPDF_GetFieldAttr(pPageDict, "Resources"); + if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { + CPDF_Dictionary* pFonts = pDict->GetDictBy("Font"); + if (pFonts) { + CPDF_Dictionary* pElement = pFonts->GetDictBy(csFontNameTag); + if (pElement) { + CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement); + if (pFont) { + return pFont; + } + } + } + } + return nullptr; +} + +int CPDF_FormControl::GetControlAlignment() { + if (!m_pWidgetDict) { + return 0; + } + if (m_pWidgetDict->KeyExist("Q")) { + return m_pWidgetDict->GetIntegerBy("Q", 0); + } + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "Q"); + if (pObj) + return pObj->GetInteger(); + return m_pField->m_pForm->GetFormAlignment(); +} + +CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {} + +bool CPDF_ApSettings::HasMKEntry(const CFX_ByteStringC& csEntry) const { + return m_pDict && m_pDict->KeyExist(csEntry); +} + +int CPDF_ApSettings::GetRotation() const { + return m_pDict ? m_pDict->GetIntegerBy("R") : 0; +} + +FX_ARGB CPDF_ApSettings::GetColor(int& iColorType, + const CFX_ByteStringC& csEntry) const { + iColorType = COLORTYPE_TRANSPARENT; + if (!m_pDict) + return 0; + + CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); + if (!pEntry) + return 0; + + FX_ARGB color = 0; + FX_DWORD dwCount = pEntry->GetCount(); + if (dwCount == 1) { + iColorType = COLORTYPE_GRAY; + FX_FLOAT g = pEntry->GetNumberAt(0) * 255; + color = ArgbEncode(255, (int)g, (int)g, (int)g); + } else if (dwCount == 3) { + iColorType = COLORTYPE_RGB; + FX_FLOAT r = pEntry->GetNumberAt(0) * 255; + FX_FLOAT g = pEntry->GetNumberAt(1) * 255; + FX_FLOAT b = pEntry->GetNumberAt(2) * 255; + color = ArgbEncode(255, (int)r, (int)g, (int)b); + } else if (dwCount == 4) { + iColorType = COLORTYPE_CMYK; + FX_FLOAT c = pEntry->GetNumberAt(0); + FX_FLOAT m = pEntry->GetNumberAt(1); + FX_FLOAT y = pEntry->GetNumberAt(2); + FX_FLOAT k = pEntry->GetNumberAt(3); + FX_FLOAT r = 1.0f - std::min(1.0f, c + k); + FX_FLOAT g = 1.0f - std::min(1.0f, m + k); + FX_FLOAT b = 1.0f - std::min(1.0f, y + k); + color = ArgbEncode(255, (int)(r * 255), (int)(g * 255), (int)(b * 255)); + } + return color; +} + +FX_FLOAT CPDF_ApSettings::GetOriginalColor( + int index, + const CFX_ByteStringC& csEntry) const { + if (!m_pDict) + return 0; + + CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); + return pEntry ? pEntry->GetNumberAt(index) : 0; +} + +void CPDF_ApSettings::GetOriginalColor(int& iColorType, + FX_FLOAT fc[4], + const CFX_ByteStringC& csEntry) const { + iColorType = COLORTYPE_TRANSPARENT; + for (int i = 0; i < 4; i++) { + fc[i] = 0; + } + if (!m_pDict) { + return; + } + CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); + if (!pEntry) { + return; + } + FX_DWORD dwCount = pEntry->GetCount(); + if (dwCount == 1) { + iColorType = COLORTYPE_GRAY; + fc[0] = pEntry->GetNumberAt(0); + } else if (dwCount == 3) { + iColorType = COLORTYPE_RGB; + fc[0] = pEntry->GetNumberAt(0); + fc[1] = pEntry->GetNumberAt(1); + fc[2] = pEntry->GetNumberAt(2); + } else if (dwCount == 4) { + iColorType = COLORTYPE_CMYK; + fc[0] = pEntry->GetNumberAt(0); + fc[1] = pEntry->GetNumberAt(1); + fc[2] = pEntry->GetNumberAt(2); + fc[3] = pEntry->GetNumberAt(3); + } +} + +CFX_WideString CPDF_ApSettings::GetCaption( + const CFX_ByteStringC& csEntry) const { + return m_pDict ? m_pDict->GetUnicodeTextBy(csEntry) : CFX_WideString(); +} + +CPDF_Stream* CPDF_ApSettings::GetIcon(const CFX_ByteStringC& csEntry) const { + return m_pDict ? m_pDict->GetStreamBy(csEntry) : nullptr; +} + +CPDF_IconFit CPDF_ApSettings::GetIconFit() const { + return CPDF_IconFit(m_pDict ? m_pDict->GetDictBy("IF") : nullptr); +} + +int CPDF_ApSettings::GetTextPosition() const { + return m_pDict ? m_pDict->GetIntegerBy("TP", TEXTPOS_CAPTION) + : TEXTPOS_CAPTION; +} diff --git a/core/fpdfdoc/doc_formfield.cpp b/core/fpdfdoc/doc_formfield.cpp new file mode 100644 index 0000000000..7ad8cacea9 --- /dev/null +++ b/core/fpdfdoc/doc_formfield.cpp @@ -0,0 +1,1097 @@ +// 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/fpdfdoc/doc_utils.h" +#include "core/include/fpdfapi/cfdf_document.h" +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_number.h" +#include "core/include/fpdfapi/cpdf_simple_parser.h" +#include "core/include/fpdfapi/cpdf_string.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +FX_BOOL PDF_FormField_IsUnison(CPDF_FormField* pField) { + FX_BOOL bUnison = FALSE; + if (pField->GetType() == CPDF_FormField::CheckBox) { + bUnison = TRUE; + } else { + FX_DWORD dwFlags = pField->GetFieldFlags(); + bUnison = ((dwFlags & 0x2000000) != 0); + } + return bUnison; +} +CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict) { + m_pDict = pDict; + m_Type = Unknown; + m_pForm = pForm; + m_pFont = NULL; + m_FontSize = 0; + SyncFieldFlags(); +} +CPDF_FormField::~CPDF_FormField() {} +void CPDF_FormField::SyncFieldFlags() { + CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT") + ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString() + : CFX_ByteString(); + FX_DWORD flags = FPDF_GetFieldAttr(m_pDict, "Ff") + ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger() + : 0; + m_Flags = 0; + if (flags & 1) { + m_Flags |= FORMFIELD_READONLY; + } + if (flags & 2) { + m_Flags |= FORMFIELD_REQUIRED; + } + if (flags & 4) { + m_Flags |= FORMFIELD_NOEXPORT; + } + if (type_name == "Btn") { + if (flags & 0x8000) { + m_Type = RadioButton; + if (flags & 0x4000) { + m_Flags |= FORMRADIO_NOTOGGLEOFF; + } + if (flags & 0x2000000) { + m_Flags |= FORMRADIO_UNISON; + } + } else if (flags & 0x10000) { + m_Type = PushButton; + } else { + m_Type = CheckBox; + } + } else if (type_name == "Tx") { + if (flags & 0x100000) { + m_Type = File; + } else if (flags & 0x2000000) { + m_Type = RichText; + } else { + m_Type = Text; + if (flags & 0x1000) { + m_Flags |= FORMTEXT_MULTILINE; + } + if (flags & 0x2000) { + m_Flags |= FORMTEXT_PASSWORD; + } + if (flags & 0x800000) { + m_Flags |= FORMTEXT_NOSCROLL; + } + if (flags & 0x100000) { + m_Flags |= FORMTEXT_COMB; + } + } + LoadDA(); + } else if (type_name == "Ch") { + if (flags & 0x20000) { + m_Type = ComboBox; + if (flags & 0x40000) { + m_Flags |= FORMCOMBO_EDIT; + } + } else { + m_Type = ListBox; + if (flags & 0x200000) { + m_Flags |= FORMLIST_MULTISELECT; + } + } + LoadDA(); + } else if (type_name == "Sig") { + m_Type = Sign; + } +} +CFX_WideString CPDF_FormField::GetFullName() { + return ::GetFullName(m_pDict); +} +FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) { + switch (m_Type) { + case CPDF_FormField::CheckBox: + case CPDF_FormField::RadioButton: { + int iCount = CountControls(); + if (iCount) { + // TODO(weili): Check whether anything special needs to be done for + // unison field. Otherwise, merge these branches. + if (PDF_FormField_IsUnison(this)) { + for (int i = 0; i < iCount; i++) { + CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); + } + } else { + for (int i = 0; i < iCount; i++) { + CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); + } + } + } + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); + } + } break; + case CPDF_FormField::ComboBox: { + CFX_WideString csValue; + ClearSelection(); + int iIndex = GetDefaultSelectedItem(); + if (iIndex >= 0) { + csValue = GetOptionLabel(iIndex); + } + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + if (iRet < 0) { + return FALSE; + } + } + SetItemSelection(iIndex, TRUE); + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + } break; + case CPDF_FormField::ListBox: { + CFX_WideString csValue; + ClearSelection(); + int iIndex = GetDefaultSelectedItem(); + if (iIndex >= 0) { + csValue = GetOptionLabel(iIndex); + } + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + if (iRet < 0) { + return FALSE; + } + } + SetItemSelection(iIndex, TRUE); + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterSelectionChange(this); + } + } break; + case CPDF_FormField::Text: + case CPDF_FormField::RichText: + case CPDF_FormField::File: + default: { + CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV"); + CFX_WideString csDValue; + if (pDV) { + csDValue = pDV->GetUnicodeText(); + } + CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); + CFX_WideString csValue; + if (pV) { + csValue = pV->GetUnicodeText(); + } + CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV"); + if (!pRV && (csDValue == csValue)) { + return FALSE; + } + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csDValue); + if (iRet < 0) { + return FALSE; + } + } + if (pDV) { + CPDF_Object* pClone = pDV->Clone(); + if (!pClone) { + return FALSE; + } + m_pDict->SetAt("V", pClone); + if (pRV) { + CPDF_Object* pCloneR = pDV->Clone(); + m_pDict->SetAt("RV", pCloneR); + } + } else { + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("RV"); + } + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + m_pForm->m_bUpdated = TRUE; + } break; + } + return TRUE; +} +int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) { + if (!pControl) { + return -1; + } + for (int i = 0; i < m_ControlList.GetSize(); i++) { + if (m_ControlList.GetAt(i) == pControl) + return i; + } + return -1; +} +int CPDF_FormField::GetFieldType() { + switch (m_Type) { + case PushButton: + return FIELDTYPE_PUSHBUTTON; + case CheckBox: + return FIELDTYPE_CHECKBOX; + case RadioButton: + return FIELDTYPE_RADIOBUTTON; + case ComboBox: + return FIELDTYPE_COMBOBOX; + case ListBox: + return FIELDTYPE_LISTBOX; + case Text: + case RichText: + case File: + return FIELDTYPE_TEXTFIELD; + case Sign: + return FIELDTYPE_SIGNATURE; + default: + break; + } + return FIELDTYPE_UNKNOWN; +} + +CPDF_AAction CPDF_FormField::GetAdditionalAction() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA"); + return CPDF_AAction(pObj ? pObj->GetDict() : nullptr); +} + +CFX_WideString CPDF_FormField::GetAlternateName() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU"); + if (!pObj) { + return L""; + } + return pObj->GetUnicodeText(); +} +CFX_WideString CPDF_FormField::GetMappingName() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM"); + if (!pObj) { + return L""; + } + return pObj->GetUnicodeText(); +} +FX_DWORD CPDF_FormField::GetFieldFlags() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff"); + if (!pObj) { + return 0; + } + return pObj->GetInteger(); +} +CFX_ByteString CPDF_FormField::GetDefaultStyle() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS"); + if (!pObj) { + return ""; + } + return pObj->GetString(); +} +CFX_WideString CPDF_FormField::GetRichTextString() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV"); + if (!pObj) { + return L""; + } + return pObj->GetUnicodeText(); +} +CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) { + if (GetType() == CheckBox || GetType() == RadioButton) { + return GetCheckValue(bDefault); + } + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V"); + if (!pValue) { + if (!bDefault) { + if (m_Type == RichText) { + pValue = FPDF_GetFieldAttr(m_pDict, "V"); + } + if (!pValue && m_Type != Text) { + pValue = FPDF_GetFieldAttr(m_pDict, "DV"); + } + } + if (!pValue) { + return CFX_WideString(); + } + } + switch (pValue->GetType()) { + case CPDF_Object::STRING: + case CPDF_Object::STREAM: + return pValue->GetUnicodeText(); + case CPDF_Object::ARRAY: + pValue = pValue->AsArray()->GetElementValue(0); + if (pValue) + return pValue->GetUnicodeText(); + break; + default: + break; + } + return CFX_WideString(); +} +CFX_WideString CPDF_FormField::GetValue() { + return GetValue(FALSE); +} +CFX_WideString CPDF_FormField::GetDefaultValue() { + return GetValue(TRUE); +} +FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, + FX_BOOL bDefault, + FX_BOOL bNotify) { + switch (m_Type) { + case CheckBox: + case RadioButton: { + SetCheckValue(value, bDefault, bNotify); + return TRUE; + } + case File: + case RichText: + case Text: + case ComboBox: { + CFX_WideString csValue = value; + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + if (iRet < 0) { + return FALSE; + } + } + int iIndex = FindOptionValue(csValue); + if (iIndex < 0) { + CFX_ByteString bsEncodeText = PDF_EncodeText(csValue); + m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText); + if (m_Type == RichText && !bDefault) { + m_pDict->SetAtString("RV", bsEncodeText); + } + m_pDict->RemoveAt("I"); + } else { + m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue)); + if (bDefault) { + } else { + ClearSelection(); + SetItemSelection(iIndex, TRUE); + } + } + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + m_pForm->m_bUpdated = TRUE; + } break; + case ListBox: { + int iIndex = FindOptionValue(value); + if (iIndex < 0) { + return FALSE; + } + if (bDefault && iIndex == GetDefaultSelectedItem()) { + return FALSE; + } + if (bNotify && m_pForm->m_pFormNotify) { + CFX_WideString csValue = value; + int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + if (iRet < 0) { + return FALSE; + } + } + if (bDefault) { + } else { + ClearSelection(); + SetItemSelection(iIndex, TRUE); + } + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterSelectionChange(this); + } + m_pForm->m_bUpdated = TRUE; + break; + } + default: + break; + } + if (CPDF_InterForm::m_bUpdateAP) { + UpdateAP(NULL); + } + return TRUE; +} +FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) { + return SetValue(value, FALSE, bNotify); +} +int CPDF_FormField::GetMaxLen() { + if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen")) + return pObj->GetInteger(); + + for (int i = 0; i < m_ControlList.GetSize(); i++) { + CPDF_FormControl* pControl = m_ControlList.GetAt(i); + if (!pControl) + continue; + + CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict; + if (pWidgetDict->KeyExist("MaxLen")) + return pWidgetDict->GetIntegerBy("MaxLen"); + } + return 0; +} +int CPDF_FormField::CountSelectedItems() { + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue) { + pValue = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pValue) + return 0; + } + + if (pValue->IsString() || pValue->IsNumber()) + return pValue->GetString().IsEmpty() ? 0 : 1; + if (CPDF_Array* pArray = pValue->AsArray()) + return pArray->GetCount(); + return 0; +} +int CPDF_FormField::GetSelectedIndex(int index) { + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue) { + pValue = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pValue) + return -1; + } + if (pValue->IsNumber()) + return pValue->GetInteger(); + + CFX_WideString sel_value; + if (pValue->IsString()) { + if (index != 0) + return -1; + sel_value = pValue->GetUnicodeText(); + } else { + CPDF_Array* pArray = pValue->AsArray(); + if (!pArray || index < 0) + return -1; + + CPDF_Object* elementValue = pArray->GetElementValue(index); + sel_value = + elementValue ? elementValue->GetUnicodeText() : CFX_WideString(); + } + if (index < CountSelectedOptions()) { + int iOptIndex = GetSelectedOptionIndex(index); + CFX_WideString csOpt = GetOptionValue(iOptIndex); + if (csOpt == sel_value) { + return iOptIndex; + } + } + int nOpts = CountOptions(); + for (int i = 0; i < nOpts; i++) { + if (sel_value == GetOptionValue(i)) { + return i; + } + } + return -1; +} +FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) { + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) { + csValue = GetOptionLabel(iIndex); + } + if (GetType() == ListBox) { + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + } + if (GetType() == ComboBox) { + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + } + if (iRet < 0) { + return FALSE; + } + } + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("I"); + if (bNotify && m_pForm->m_pFormNotify) { + if (GetType() == ListBox) { + m_pForm->m_pFormNotify->AfterSelectionChange(this); + } + if (GetType() == ComboBox) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + } + if (CPDF_InterForm::m_bUpdateAP) { + UpdateAP(NULL); + } + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +FX_BOOL CPDF_FormField::IsItemSelected(int index) { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + if (index < 0 || index >= CountOptions()) { + return FALSE; + } + if (IsOptionSelected(index)) { + return TRUE; + } + CFX_WideString opt_value = GetOptionValue(index); + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue) { + pValue = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pValue) { + return FALSE; + } + } + + if (pValue->IsString()) + return pValue->GetUnicodeText() == opt_value; + + if (pValue->IsNumber()) { + if (pValue->GetString().IsEmpty()) + return FALSE; + return (pValue->GetInteger() == index); + } + + CPDF_Array* pArray = pValue->AsArray(); + if (!pArray) + return FALSE; + + int iPos = -1; + for (int j = 0; j < CountSelectedOptions(); j++) { + if (GetSelectedOptionIndex(j) == index) { + iPos = j; + break; + } + } + for (FX_DWORD i = 0; i < pArray->GetCount(); i++) + if (pArray->GetElementValue(i)->GetUnicodeText() == opt_value && + (int)i == iPos) { + return TRUE; + } + return FALSE; +} +FX_BOOL CPDF_FormField::SetItemSelection(int index, + FX_BOOL bSelected, + FX_BOOL bNotify) { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + if (index < 0 || index >= CountOptions()) { + return FALSE; + } + CFX_WideString opt_value = GetOptionValue(index); + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + if (GetType() == ListBox) { + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, opt_value); + } + if (GetType() == ComboBox) { + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, opt_value); + } + if (iRet < 0) { + return FALSE; + } + } + if (!bSelected) { + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (pValue) { + if (m_Type == ListBox) { + SelectOption(index, FALSE); + if (pValue->IsString()) { + if (pValue->GetUnicodeText() == opt_value) { + m_pDict->RemoveAt("V"); + } + } else if (pValue->IsArray()) { + CPDF_Array* pArray = new CPDF_Array; + int iCount = CountOptions(); + for (int i = 0; i < iCount; i++) { + if (i != index) { + if (IsItemSelected(i)) { + opt_value = GetOptionValue(i); + pArray->AddString(PDF_EncodeText(opt_value)); + } + } + } + if (pArray->GetCount() < 1) { + pArray->Release(); + } else { + m_pDict->SetAt("V", pArray); + } + } + } else if (m_Type == ComboBox) { + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("I"); + } + } + } else { + if (m_Type == ListBox) { + SelectOption(index, TRUE); + if (!(m_Flags & FORMLIST_MULTISELECT)) { + m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); + } else { + CPDF_Array* pArray = new CPDF_Array; + int iCount = CountOptions(); + for (int i = 0; i < iCount; i++) { + FX_BOOL bSelected; + if (i != index) { + bSelected = IsItemSelected(i); + } else { + bSelected = TRUE; + } + if (bSelected) { + opt_value = GetOptionValue(i); + pArray->AddString(PDF_EncodeText(opt_value)); + } + } + m_pDict->SetAt("V", pArray); + } + } else if (m_Type == ComboBox) { + m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); + CPDF_Array* pI = new CPDF_Array; + pI->AddInteger(index); + m_pDict->SetAt("I", pI); + } + } + if (bNotify && m_pForm->m_pFormNotify) { + if (GetType() == ListBox) { + m_pForm->m_pFormNotify->AfterSelectionChange(this); + } + if (GetType() == ComboBox) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + } + if (CPDF_InterForm::m_bUpdateAP) { + UpdateAP(NULL); + } + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + if (index < 0 || index >= CountOptions()) { + return FALSE; + } + int iDVIndex = GetDefaultSelectedItem(); + if (iDVIndex < 0) { + return FALSE; + } + return (iDVIndex == index); +} +int CPDF_FormField::GetDefaultSelectedItem() { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV"); + if (!pValue) { + return -1; + } + CFX_WideString csDV = pValue->GetUnicodeText(); + if (csDV.IsEmpty()) { + return -1; + } + int iCount = CountOptions(); + for (int i = 0; i < iCount; i++) { + if (csDV == GetOptionValue(i)) { + return i; + } + } + return -1; +} +void CPDF_FormField::UpdateAP(CPDF_FormControl* pControl) { + if (m_Type == PushButton) { + return; + } + if (m_Type == RadioButton || m_Type == CheckBox) { + return; + } + if (!m_pForm->m_bGenerateAP) { + return; + } + for (int i = 0; i < CountControls(); i++) { + CPDF_FormControl* pControl = GetControl(i); + FPDF_GenerateAP(m_pForm->m_pDocument, pControl->m_pWidgetDict); + } +} +int CPDF_FormField::CountOptions() { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); + return pArray ? pArray->GetCount() : 0; +} +CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); + if (!pArray) + return CFX_WideString(); + + CPDF_Object* pOption = pArray->GetElementValue(index); + if (!pOption) + return CFX_WideString(); + if (CPDF_Array* pOptionArray = pOption->AsArray()) + pOption = pOptionArray->GetElementValue(sub_index); + + CPDF_String* pString = ToString(pOption); + return pString ? pString->GetUnicodeText() : CFX_WideString(); +} +CFX_WideString CPDF_FormField::GetOptionLabel(int index) { + return GetOptionText(index, 1); +} +CFX_WideString CPDF_FormField::GetOptionValue(int index) { + return GetOptionText(index, 0); +} +int CPDF_FormField::FindOption(CFX_WideString csOptLabel) { + int iCount = CountOptions(); + for (int i = 0; i < iCount; i++) { + CFX_WideString csValue = GetOptionValue(i); + if (csValue == csOptLabel) { + return i; + } + } + return -1; +} +int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue, + int iStartIndex) { + if (iStartIndex < 0) { + iStartIndex = 0; + } + int iCount = CountOptions(); + for (; iStartIndex < iCount; iStartIndex++) { + CFX_WideString csValue = GetOptionValue(iStartIndex); + if (csValue == csOptValue) { + return iStartIndex; + } + } + return -1; +} +#ifdef PDF_ENABLE_XFA +int CPDF_FormField::InsertOption(CFX_WideString csOptLabel, + int index, + FX_BOOL bNotify) { + if (csOptLabel.IsEmpty()) + return -1; + + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + if (GetType() == ListBox) + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csOptLabel); + if (GetType() == ComboBox) + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csOptLabel); + if (iRet < 0) + return -1; + } + + CFX_ByteString csStr = PDF_EncodeText(csOptLabel, csOptLabel.GetLength()); + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt"); + CPDF_Array* pOpt = ToArray(pValue); + if (!pOpt) { + pOpt = new CPDF_Array; + m_pDict->SetAt("Opt", pOpt); + } + + int iCount = (int)pOpt->GetCount(); + if (index < 0 || index >= iCount) { + pOpt->AddString(csStr); + index = iCount; + } else { + CPDF_String* pString = new CPDF_String(csStr, FALSE); + pOpt->InsertAt(index, pString); + } + + if (bNotify && m_pForm->m_pFormNotify) { + if (GetType() == ListBox) + m_pForm->m_pFormNotify->AfterSelectionChange(this); + if (GetType() == ComboBox) + m_pForm->m_pFormNotify->AfterValueChange(this); + } + m_pForm->m_bUpdated = TRUE; + return index; +} +FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) { + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) + csValue = GetOptionLabel(iIndex); + if (GetType() == ListBox) + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + if (GetType() == ComboBox) + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + if (iRet < 0) + return FALSE; + } + + m_pDict->RemoveAt("Opt"); + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("DV"); + m_pDict->RemoveAt("I"); + m_pDict->RemoveAt("TI"); + + if (bNotify && m_pForm->m_pFormNotify) { + if (GetType() == ListBox) + m_pForm->m_pFormNotify->AfterSelectionChange(this); + if (GetType() == ComboBox) + m_pForm->m_pFormNotify->AfterValueChange(this); + } + + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +#endif // PDF_ENABLE_XFA +FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, + bool bChecked, + bool bNotify) { + ASSERT(GetType() == CheckBox || GetType() == RadioButton); + CPDF_FormControl* pControl = GetControl(iControlIndex); + if (!pControl) { + return FALSE; + } + if (!bChecked && pControl->IsChecked() == bChecked) { + return FALSE; + } + CFX_WideString csWExport = pControl->GetExportValue(); + CFX_ByteString csBExport = PDF_EncodeText(csWExport); + int iCount = CountControls(); + FX_BOOL bUnison = PDF_FormField_IsUnison(this); + for (int i = 0; i < iCount; i++) { + CPDF_FormControl* pCtrl = GetControl(i); + if (bUnison) { + CFX_WideString csEValue = pCtrl->GetExportValue(); + if (csEValue == csWExport) { + if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) { + pCtrl->CheckControl(bChecked); + } else if (bChecked) { + pCtrl->CheckControl(FALSE); + } + } else if (bChecked) { + pCtrl->CheckControl(FALSE); + } + } else { + if (i == iControlIndex) { + pCtrl->CheckControl(bChecked); + } else if (bChecked) { + pCtrl->CheckControl(FALSE); + } + } + } + CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt"); + if (!ToArray(pOpt)) { + if (bChecked) { + m_pDict->SetAtName("V", csBExport); + } else { + CFX_ByteString csV; + CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); + if (pV) { + csV = pV->GetString(); + } + if (csV == csBExport) { + m_pDict->SetAtName("V", "Off"); + } + } + } else if (bChecked) { + CFX_ByteString csIndex; + csIndex.Format("%d", iControlIndex); + m_pDict->SetAtName("V", csIndex); + } + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); + } + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) { + ASSERT(GetType() == CheckBox || GetType() == RadioButton); + CFX_WideString csExport = L"Off"; + FX_BOOL bChecked; + int iCount = CountControls(); + for (int i = 0; i < iCount; i++) { + CPDF_FormControl* pControl = GetControl(i); + if (bDefault) { + bChecked = pControl->IsDefaultChecked(); + } else { + bChecked = pControl->IsChecked(); + } + if (bChecked) { + csExport = pControl->GetExportValue(); + break; + } + } + return csExport; +} +FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value, + FX_BOOL bDefault, + FX_BOOL bNotify) { + ASSERT(GetType() == CheckBox || GetType() == RadioButton); + int iCount = CountControls(); + for (int i = 0; i < iCount; i++) { + CPDF_FormControl* pControl = GetControl(i); + CFX_WideString csExport = pControl->GetExportValue(); + if (csExport == value) { + if (bDefault) { + } else { + CheckControl(GetControlIndex(pControl), TRUE); + } + break; + } else { + if (bDefault) { + } else { + CheckControl(GetControlIndex(pControl), FALSE); + } + } + } + if (bNotify && m_pForm->m_pFormNotify) { + m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); + } + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +int CPDF_FormField::GetTopVisibleIndex() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI"); + if (!pObj) { + return 0; + } + return pObj->GetInteger(); +} +int CPDF_FormField::CountSelectedOptions() { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pObj) { + return 0; + } + CPDF_Array* pArray = pObj->GetArray(); + if (!pArray) { + return 0; + } + return (int)pArray->GetCount(); +} +int CPDF_FormField::GetSelectedOptionIndex(int index) { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pObj) { + return -1; + } + CPDF_Array* pArray = pObj->GetArray(); + if (!pArray) { + return -1; + } + int iCount = (int)pArray->GetCount(); + if (iCount > 0 && index < iCount) { + return pArray->GetIntegerAt(index); + } + return -1; +} +FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pObj) { + return FALSE; + } + CPDF_Array* pArray = pObj->GetArray(); + if (!pArray) { + return FALSE; + } + int iCount = (int)pArray->GetCount(); + for (int i = 0; i < iCount; i++) { + if (pArray->GetIntegerAt(i) == iOptIndex) { + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_FormField::SelectOption(int iOptIndex, + FX_BOOL bSelected, + FX_BOOL bNotify) { + CPDF_Array* pArray = m_pDict->GetArrayBy("I"); + if (!pArray) { + if (!bSelected) { + return TRUE; + } + pArray = new CPDF_Array; + m_pDict->SetAt("I", pArray); + } + FX_BOOL bReturn = FALSE; + for (int i = 0; i < (int)pArray->GetCount(); i++) { + int iFind = pArray->GetIntegerAt(i); + if (iFind == iOptIndex) { + if (bSelected) { + return TRUE; + } + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + CFX_WideString csValue = GetOptionLabel(iOptIndex); + if (GetType() == ListBox) { + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + } + if (GetType() == ComboBox) { + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + } + if (iRet < 0) { + return FALSE; + } + } + pArray->RemoveAt(i); + bReturn = TRUE; + break; + } else if (iFind > iOptIndex) { + if (!bSelected) { + continue; + } + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + CFX_WideString csValue = GetOptionLabel(iOptIndex); + if (GetType() == ListBox) { + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + } + if (GetType() == ComboBox) { + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + } + if (iRet < 0) { + return FALSE; + } + } + CPDF_Number* pNum = new CPDF_Number(iOptIndex); + pArray->InsertAt(i, pNum); + bReturn = TRUE; + break; + } + } + if (!bReturn) { + if (bSelected) { + pArray->AddInteger(iOptIndex); + } + if (pArray->GetCount() == 0) { + m_pDict->RemoveAt("I"); + } + } + if (bNotify && m_pForm->m_pFormNotify) { + if (GetType() == ListBox) { + m_pForm->m_pFormNotify->AfterSelectionChange(this); + } + if (GetType() == ComboBox) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + } + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) { + if (bNotify && m_pForm->m_pFormNotify) { + int iRet = 0; + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) { + csValue = GetOptionLabel(iIndex); + } + if (GetType() == ListBox) { + iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue); + } + if (GetType() == ComboBox) { + iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue); + } + if (iRet < 0) { + return FALSE; + } + } + m_pDict->RemoveAt("I"); + if (bNotify && m_pForm->m_pFormNotify) { + if (GetType() == ListBox) { + m_pForm->m_pFormNotify->AfterSelectionChange(this); + } + if (GetType() == ComboBox) { + m_pForm->m_pFormNotify->AfterValueChange(this); + } + } + m_pForm->m_bUpdated = TRUE; + return TRUE; +} +void CPDF_FormField::LoadDA() { + CFX_ByteString DA; + if (CPDF_Object* pObj_t = FPDF_GetFieldAttr(m_pDict, "DA")) { + DA = pObj_t->GetString(); + } + if (DA.IsEmpty() && m_pForm->m_pFormDict) { + DA = m_pForm->m_pFormDict->GetStringBy("DA"); + } + if (DA.IsEmpty()) { + return; + } + CPDF_SimpleParser syntax(DA); + syntax.FindTagParamFromStart("Tf", 2); + CFX_ByteString font_name = syntax.GetWord(); + CPDF_Dictionary* pFontDict = NULL; + if (m_pForm->m_pFormDict && m_pForm->m_pFormDict->GetDictBy("DR") && + m_pForm->m_pFormDict->GetDictBy("DR")->GetDictBy("Font")) + pFontDict = m_pForm->m_pFormDict->GetDictBy("DR") + ->GetDictBy("Font") + ->GetDictBy(font_name); + + if (!pFontDict) { + return; + } + m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict); + m_FontSize = FX_atof(syntax.GetWord()); +} diff --git a/core/fpdfdoc/doc_link.cpp b/core/fpdfdoc/doc_link.cpp new file mode 100644 index 0000000000..8aedb40034 --- /dev/null +++ b/core/fpdfdoc/doc_link.cpp @@ -0,0 +1,92 @@ +// 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/include/fpdfdoc/fpdf_doc.h" + +#include <vector> + +#include "core/include/fpdfapi/cpdf_array.h" + +CPDF_LinkList::CPDF_LinkList() {} + +CPDF_LinkList::~CPDF_LinkList() {} + +const std::vector<CPDF_Dictionary*>* CPDF_LinkList::GetPageLinks( + CPDF_Page* pPage) { + FX_DWORD objnum = pPage->m_pFormDict->GetObjNum(); + if (objnum == 0) + return nullptr; + + auto it = m_PageMap.find(objnum); + if (it != m_PageMap.end()) + return &it->second; + + // std::map::operator[] forces the creation of a map entry. + std::vector<CPDF_Dictionary*>& page_link_list = m_PageMap[objnum]; + LoadPageLinks(pPage, &page_link_list); + return &page_link_list; +} + +CPDF_Link CPDF_LinkList::GetLinkAtPoint(CPDF_Page* pPage, + FX_FLOAT pdf_x, + FX_FLOAT pdf_y, + int* z_order) { + const std::vector<CPDF_Dictionary*>* pPageLinkList = GetPageLinks(pPage); + if (!pPageLinkList) + return CPDF_Link(); + + for (size_t i = pPageLinkList->size(); i > 0; --i) { + size_t annot_index = i - 1; + CPDF_Dictionary* pAnnot = (*pPageLinkList)[annot_index]; + if (!pAnnot) + continue; + + CPDF_Link link(pAnnot); + CFX_FloatRect rect = link.GetRect(); + if (!rect.Contains(pdf_x, pdf_y)) + continue; + + if (z_order) + *z_order = annot_index; + return link; + } + return CPDF_Link(); +} + +void CPDF_LinkList::LoadPageLinks(CPDF_Page* pPage, + std::vector<CPDF_Dictionary*>* pList) { + CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayBy("Annots"); + if (!pAnnotList) + return; + + for (FX_DWORD i = 0; i < pAnnotList->GetCount(); ++i) { + CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(i); + bool add_link = (pAnnot && pAnnot->GetStringBy("Subtype") == "Link"); + // Add non-links as nullptrs to preserve z-order. + pList->push_back(add_link ? pAnnot : nullptr); + } +} + +CFX_FloatRect CPDF_Link::GetRect() { + return m_pDict->GetRectBy("Rect"); +} +CPDF_Dest CPDF_Link::GetDest(CPDF_Document* pDoc) { + CPDF_Object* pDest = m_pDict->GetElementValue("Dest"); + if (!pDest) + return CPDF_Dest(); + + if (pDest->IsString() || pDest->IsName()) { + CPDF_NameTree name_tree(pDoc, "Dests"); + CFX_ByteStringC name = pDest->GetString(); + return CPDF_Dest(name_tree.LookupNamedDest(pDoc, name)); + } + if (CPDF_Array* pArray = pDest->AsArray()) + return CPDF_Dest(pArray); + return CPDF_Dest(); +} +CPDF_Action CPDF_Link::GetAction() { + return CPDF_Action(m_pDict->GetDictBy("A")); +} diff --git a/core/fpdfdoc/doc_metadata.cpp b/core/fpdfdoc/doc_metadata.cpp new file mode 100644 index 0000000000..78364c4cbf --- /dev/null +++ b/core/fpdfdoc/doc_metadata.cpp @@ -0,0 +1,29 @@ +// 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/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfdoc/fpdf_doc.h" +#include "core/include/fxcrt/fx_xml.h" + +CPDF_Metadata::CPDF_Metadata(CPDF_Document* pDoc) { + CPDF_Dictionary* pRoot = pDoc->GetRoot(); + if (!pRoot) + return; + + CPDF_Stream* pStream = pRoot->GetStreamBy("Metadata"); + if (!pStream) + return; + + CPDF_StreamAcc acc; + acc.LoadAllData(pStream, FALSE); + m_pXmlElement.reset(CXML_Element::Parse(acc.GetData(), acc.GetSize())); +} + +CPDF_Metadata::~CPDF_Metadata() {} + +const CXML_Element* CPDF_Metadata::GetRoot() const { + return m_pXmlElement.get(); +} diff --git a/core/fpdfdoc/doc_ocg.cpp b/core/fpdfdoc/doc_ocg.cpp new file mode 100644 index 0000000000..3af745580c --- /dev/null +++ b/core/fpdfdoc/doc_ocg.cpp @@ -0,0 +1,284 @@ +// 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/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +static int32_t FPDFDOC_OCG_FindGroup(const CPDF_Object* pObject, + const CPDF_Dictionary* pGroupDict) { + if (!pObject || !pGroupDict) + return -1; + + if (const CPDF_Array* pArray = pObject->AsArray()) { + FX_DWORD dwCount = pArray->GetCount(); + for (FX_DWORD i = 0; i < dwCount; i++) { + if (pArray->GetDictAt(i) == pGroupDict) + return i; + } + return -1; + } + return pObject->GetDict() == pGroupDict ? 0 : -1; +} +static FX_BOOL FPDFDOC_OCG_HasIntent(const CPDF_Dictionary* pDict, + const CFX_ByteStringC& csElement, + const CFX_ByteStringC& csDef = "") { + CPDF_Object* pIntent = pDict->GetElementValue("Intent"); + if (!pIntent) { + return csElement == csDef; + } + CFX_ByteString bsIntent; + if (CPDF_Array* pArray = pIntent->AsArray()) { + FX_DWORD dwCount = pArray->GetCount(); + for (FX_DWORD i = 0; i < dwCount; i++) { + bsIntent = pArray->GetStringAt(i); + if (bsIntent == "All" || bsIntent == csElement) + return TRUE; + } + return FALSE; + } + bsIntent = pIntent->GetString(); + return bsIntent == "All" || bsIntent == csElement; +} +static CPDF_Dictionary* FPDFDOC_OCG_GetConfig(CPDF_Document* pDoc, + const CPDF_Dictionary* pOCGDict, + const CFX_ByteStringC& bsState) { + FXSYS_assert(pDoc && pOCGDict); + CPDF_Dictionary* pOCProperties = pDoc->GetRoot()->GetDictBy("OCProperties"); + if (!pOCProperties) { + return NULL; + } + CPDF_Array* pOCGs = pOCProperties->GetArrayBy("OCGs"); + if (!pOCGs) { + return NULL; + } + if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) { + return NULL; + } + CPDF_Dictionary* pConfig = pOCProperties->GetDictBy("D"); + CPDF_Array* pConfigs = pOCProperties->GetArrayBy("Configs"); + if (pConfigs) { + CPDF_Dictionary* pFind; + int32_t iCount = pConfigs->GetCount(); + for (int32_t i = 0; i < iCount; i++) { + pFind = pConfigs->GetDictAt(i); + if (!pFind) { + continue; + } + if (!FPDFDOC_OCG_HasIntent(pFind, "View", "View")) { + continue; + } + pConfig = pFind; + break; + } + } + return pConfig; +} +static CFX_ByteString FPDFDOC_OCG_GetUsageTypeString( + CPDF_OCContext::UsageType eType) { + CFX_ByteString csState = "View"; + if (eType == CPDF_OCContext::Design) { + csState = "Design"; + } else if (eType == CPDF_OCContext::Print) { + csState = "Print"; + } else if (eType == CPDF_OCContext::Export) { + csState = "Export"; + } + return csState; +} +CPDF_OCContext::CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType) { + FXSYS_assert(pDoc); + m_pDocument = pDoc; + m_eUsageType = eUsageType; +} +CPDF_OCContext::~CPDF_OCContext() { + m_OCGStates.clear(); +} +FX_BOOL CPDF_OCContext::LoadOCGStateFromConfig(const CFX_ByteStringC& csConfig, + const CPDF_Dictionary* pOCGDict, + FX_BOOL& bValidConfig) const { + CPDF_Dictionary* pConfig = + FPDFDOC_OCG_GetConfig(m_pDocument, pOCGDict, csConfig); + if (!pConfig) { + return TRUE; + } + bValidConfig = TRUE; + FX_BOOL bState = pConfig->GetStringBy("BaseState", "ON") != "OFF"; + CPDF_Array* pArray = pConfig->GetArrayBy("ON"); + if (pArray) { + if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) { + bState = TRUE; + } + } + pArray = pConfig->GetArrayBy("OFF"); + if (pArray) { + if (FPDFDOC_OCG_FindGroup(pArray, pOCGDict) >= 0) { + bState = FALSE; + } + } + pArray = pConfig->GetArrayBy("AS"); + if (pArray) { + CFX_ByteString csFind = csConfig + "State"; + int32_t iCount = pArray->GetCount(); + for (int32_t i = 0; i < iCount; i++) { + CPDF_Dictionary* pUsage = pArray->GetDictAt(i); + if (!pUsage) { + continue; + } + if (pUsage->GetStringBy("Event", "View") != csConfig) { + continue; + } + CPDF_Array* pOCGs = pUsage->GetArrayBy("OCGs"); + if (!pOCGs) { + continue; + } + if (FPDFDOC_OCG_FindGroup(pOCGs, pOCGDict) < 0) { + continue; + } + CPDF_Dictionary* pState = pUsage->GetDictBy(csConfig); + if (!pState) { + continue; + } + bState = pState->GetStringBy(csFind) != "OFF"; + } + } + return bState; +} +FX_BOOL CPDF_OCContext::LoadOCGState(const CPDF_Dictionary* pOCGDict) const { + if (!FPDFDOC_OCG_HasIntent(pOCGDict, "View", "View")) { + return TRUE; + } + CFX_ByteString csState = FPDFDOC_OCG_GetUsageTypeString(m_eUsageType); + CPDF_Dictionary* pUsage = pOCGDict->GetDictBy("Usage"); + if (pUsage) { + CPDF_Dictionary* pState = pUsage->GetDictBy(csState); + if (pState) { + CFX_ByteString csFind = csState + "State"; + if (pState->KeyExist(csFind)) { + return pState->GetStringBy(csFind) != "OFF"; + } + } + if (csState != "View") { + pState = pUsage->GetDictBy("View"); + if (pState && pState->KeyExist("ViewState")) { + return pState->GetStringBy("ViewState") != "OFF"; + } + } + } + FX_BOOL bDefValid = FALSE; + return LoadOCGStateFromConfig(csState, pOCGDict, bDefValid); +} + +FX_BOOL CPDF_OCContext::GetOCGVisible(const CPDF_Dictionary* pOCGDict) { + if (!pOCGDict) + return FALSE; + + const auto it = m_OCGStates.find(pOCGDict); + if (it != m_OCGStates.end()) + return it->second; + + FX_BOOL bState = LoadOCGState(pOCGDict); + m_OCGStates[pOCGDict] = bState; + return bState; +} + +FX_BOOL CPDF_OCContext::GetOCGVE(CPDF_Array* pExpression, + FX_BOOL bFromConfig, + int nLevel) { + if (nLevel > 32) { + return FALSE; + } + if (!pExpression) { + return FALSE; + } + int32_t iCount = pExpression->GetCount(); + CPDF_Object* pOCGObj; + CFX_ByteString csOperator = pExpression->GetStringAt(0); + if (csOperator == "Not") { + pOCGObj = pExpression->GetElementValue(1); + if (!pOCGObj) + return FALSE; + if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) + return !(bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict)); + if (CPDF_Array* pArray = pOCGObj->AsArray()) + return !GetOCGVE(pArray, bFromConfig, nLevel + 1); + return FALSE; + } + if (csOperator == "Or" || csOperator == "And") { + FX_BOOL bValue = FALSE; + for (int32_t i = 1; i < iCount; i++) { + pOCGObj = pExpression->GetElementValue(1); + if (!pOCGObj) { + continue; + } + FX_BOOL bItem = FALSE; + if (CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) + bItem = bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict); + else if (CPDF_Array* pArray = pOCGObj->AsArray()) + bItem = GetOCGVE(pArray, bFromConfig, nLevel + 1); + + if (i == 1) { + bValue = bItem; + } else { + if (csOperator == "Or") { + bValue = bValue || bItem; + } else { + bValue = bValue && bItem; + } + } + } + return bValue; + } + return FALSE; +} +FX_BOOL CPDF_OCContext::LoadOCMDState(const CPDF_Dictionary* pOCMDDict, + FX_BOOL bFromConfig) { + CPDF_Array* pVE = pOCMDDict->GetArrayBy("VE"); + if (pVE) { + return GetOCGVE(pVE, bFromConfig); + } + CFX_ByteString csP = pOCMDDict->GetStringBy("P", "AnyOn"); + CPDF_Object* pOCGObj = pOCMDDict->GetElementValue("OCGs"); + if (!pOCGObj) + return TRUE; + if (const CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) + return bFromConfig ? LoadOCGState(pDict) : GetOCGVisible(pDict); + + CPDF_Array* pArray = pOCGObj->AsArray(); + if (!pArray) + return TRUE; + + FX_BOOL bState = FALSE; + if (csP == "AllOn" || csP == "AllOff") { + bState = TRUE; + } + int32_t iCount = pArray->GetCount(); + for (int32_t i = 0; i < iCount; i++) { + FX_BOOL bItem = TRUE; + CPDF_Dictionary* pItemDict = pArray->GetDictAt(i); + if (pItemDict) + bItem = bFromConfig ? LoadOCGState(pItemDict) : GetOCGVisible(pItemDict); + + if ((csP == "AnyOn" && bItem) || (csP == "AnyOff" && !bItem)) + return TRUE; + if ((csP == "AllOn" && !bItem) || (csP == "AllOff" && bItem)) + return FALSE; + } + return bState; +} +FX_BOOL CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) { + if (!pOCGDict) { + return TRUE; + } + CFX_ByteString csType = pOCGDict->GetStringBy("Type", "OCG"); + if (csType == "OCG") { + return GetOCGVisible(pOCGDict); + } + return LoadOCMDState(pOCGDict, FALSE); +} +void CPDF_OCContext::ResetOCContext() { + m_OCGStates.clear(); +} diff --git a/core/fpdfdoc/doc_tagged.cpp b/core/fpdfdoc/doc_tagged.cpp new file mode 100644 index 0000000000..015f4db878 --- /dev/null +++ b/core/fpdfdoc/doc_tagged.cpp @@ -0,0 +1,440 @@ +// 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 <map> + +#include "core/fpdfdoc/doc_utils.h" +#include "core/fpdfdoc/tagged_int.h" +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_dictionary.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_reference.h" +#include "core/include/fpdfapi/fpdf_page.h" +#include "core/include/fpdfdoc/fpdf_tagged.h" + +const int nMaxRecursion = 32; +static FX_BOOL IsTagged(const CPDF_Document* pDoc) { + CPDF_Dictionary* pCatalog = pDoc->GetRoot(); + CPDF_Dictionary* pMarkInfo = pCatalog->GetDictBy("MarkInfo"); + return pMarkInfo && pMarkInfo->GetIntegerBy("Marked"); +} +CPDF_StructTree* CPDF_StructTree::LoadPage(const CPDF_Document* pDoc, + const CPDF_Dictionary* pPageDict) { + if (!IsTagged(pDoc)) { + return NULL; + } + CPDF_StructTreeImpl* pTree = new CPDF_StructTreeImpl(pDoc); + pTree->LoadPageTree(pPageDict); + return pTree; +} +CPDF_StructTree* CPDF_StructTree::LoadDoc(const CPDF_Document* pDoc) { + if (!IsTagged(pDoc)) { + return NULL; + } + CPDF_StructTreeImpl* pTree = new CPDF_StructTreeImpl(pDoc); + pTree->LoadDocTree(); + return pTree; +} +CPDF_StructTreeImpl::CPDF_StructTreeImpl(const CPDF_Document* pDoc) { + CPDF_Dictionary* pCatalog = pDoc->GetRoot(); + m_pTreeRoot = pCatalog->GetDictBy("StructTreeRoot"); + if (!m_pTreeRoot) { + return; + } + m_pRoleMap = m_pTreeRoot->GetDictBy("RoleMap"); +} +CPDF_StructTreeImpl::~CPDF_StructTreeImpl() { + for (int i = 0; i < m_Kids.GetSize(); i++) + if (m_Kids[i]) { + m_Kids[i]->Release(); + } +} +void CPDF_StructTreeImpl::LoadDocTree() { + m_pPage = nullptr; + if (!m_pTreeRoot) + return; + + CPDF_Object* pKids = m_pTreeRoot->GetElementValue("K"); + if (!pKids) + return; + if (CPDF_Dictionary* pDict = pKids->AsDictionary()) { + CPDF_StructElementImpl* pStructElementImpl = + new CPDF_StructElementImpl(this, nullptr, pDict); + m_Kids.Add(pStructElementImpl); + return; + } + CPDF_Array* pArray = pKids->AsArray(); + if (!pArray) + return; + + for (FX_DWORD i = 0; i < pArray->GetCount(); i++) { + CPDF_Dictionary* pKid = pArray->GetDictAt(i); + CPDF_StructElementImpl* pStructElementImpl = + new CPDF_StructElementImpl(this, nullptr, pKid); + m_Kids.Add(pStructElementImpl); + } +} +void CPDF_StructTreeImpl::LoadPageTree(const CPDF_Dictionary* pPageDict) { + m_pPage = pPageDict; + if (!m_pTreeRoot) + return; + + CPDF_Object* pKids = m_pTreeRoot->GetElementValue("K"); + if (!pKids) + return; + + FX_DWORD dwKids = 0; + if (pKids->IsDictionary()) + dwKids = 1; + else if (CPDF_Array* pArray = pKids->AsArray()) + dwKids = pArray->GetCount(); + else + return; + + FX_DWORD i; + m_Kids.SetSize(dwKids); + for (i = 0; i < dwKids; i++) { + m_Kids[i] = NULL; + } + std::map<CPDF_Dictionary*, CPDF_StructElementImpl*> element_map; + CPDF_Dictionary* pParentTree = m_pTreeRoot->GetDictBy("ParentTree"); + if (!pParentTree) { + return; + } + CPDF_NumberTree parent_tree(pParentTree); + int parents_id = pPageDict->GetIntegerBy("StructParents", -1); + if (parents_id >= 0) { + CPDF_Array* pParentArray = ToArray(parent_tree.LookupValue(parents_id)); + if (!pParentArray) + return; + + for (i = 0; i < pParentArray->GetCount(); i++) { + CPDF_Dictionary* pParent = pParentArray->GetDictAt(i); + if (!pParent) { + continue; + } + AddPageNode(pParent, element_map); + } + } +} +CPDF_StructElementImpl* CPDF_StructTreeImpl::AddPageNode( + CPDF_Dictionary* pDict, + std::map<CPDF_Dictionary*, CPDF_StructElementImpl*>& map, + int nLevel) { + if (nLevel > nMaxRecursion) + return NULL; + + auto it = map.find(pDict); + if (it != map.end()) + return it->second; + + CPDF_StructElementImpl* pElement = + new CPDF_StructElementImpl(this, NULL, pDict); + map[pDict] = pElement; + CPDF_Dictionary* pParent = pDict->GetDictBy("P"); + if (!pParent || pParent->GetStringBy("Type") == "StructTreeRoot") { + if (!AddTopLevelNode(pDict, pElement)) { + pElement->Release(); + map.erase(pDict); + } + } else { + CPDF_StructElementImpl* pParentElement = + AddPageNode(pParent, map, nLevel + 1); + FX_BOOL bSave = FALSE; + for (int i = 0; i < pParentElement->m_Kids.GetSize(); i++) { + if (pParentElement->m_Kids[i].m_Type != CPDF_StructKid::Element) { + continue; + } + if (pParentElement->m_Kids[i].m_Element.m_pDict != pDict) { + continue; + } + pParentElement->m_Kids[i].m_Element.m_pElement = pElement->Retain(); + bSave = TRUE; + } + if (!bSave) { + pElement->Release(); + map.erase(pDict); + } + } + return pElement; +} +FX_BOOL CPDF_StructTreeImpl::AddTopLevelNode(CPDF_Dictionary* pDict, + CPDF_StructElementImpl* pElement) { + CPDF_Object* pObj = m_pTreeRoot->GetElementValue("K"); + if (!pObj) { + return FALSE; + } + if (pObj->IsDictionary()) { + if (pObj->GetObjNum() == pDict->GetObjNum()) { + if (m_Kids[0]) { + m_Kids[0]->Release(); + } + m_Kids[0] = pElement->Retain(); + } else { + return FALSE; + } + } + if (CPDF_Array* pTopKids = pObj->AsArray()) { + FX_DWORD i; + FX_BOOL bSave = FALSE; + for (i = 0; i < pTopKids->GetCount(); i++) { + CPDF_Reference* pKidRef = ToReference(pTopKids->GetElement(i)); + if (!pKidRef) + continue; + if (pKidRef->GetRefObjNum() != pDict->GetObjNum()) + continue; + + if (m_Kids[i]) + m_Kids[i]->Release(); + m_Kids[i] = pElement->Retain(); + bSave = TRUE; + } + if (!bSave) + return FALSE; + } + return TRUE; +} +CPDF_StructElementImpl::CPDF_StructElementImpl(CPDF_StructTreeImpl* pTree, + CPDF_StructElementImpl* pParent, + CPDF_Dictionary* pDict) + : m_RefCount(0) { + m_pTree = pTree; + m_pDict = pDict; + m_Type = pDict->GetStringBy("S"); + if (pTree->m_pRoleMap) { + CFX_ByteString mapped = pTree->m_pRoleMap->GetStringBy(m_Type); + if (!mapped.IsEmpty()) { + m_Type = mapped; + } + } + m_pParent = pParent; + LoadKids(pDict); +} +CPDF_StructElementImpl::~CPDF_StructElementImpl() { + for (int i = 0; i < m_Kids.GetSize(); i++) { + if (m_Kids[i].m_Type == CPDF_StructKid::Element && + m_Kids[i].m_Element.m_pElement) { + ((CPDF_StructElementImpl*)m_Kids[i].m_Element.m_pElement)->Release(); + } + } +} +CPDF_StructElementImpl* CPDF_StructElementImpl::Retain() { + m_RefCount++; + return this; +} +void CPDF_StructElementImpl::Release() { + if (--m_RefCount < 1) { + delete this; + } +} +void CPDF_StructElementImpl::LoadKids(CPDF_Dictionary* pDict) { + CPDF_Object* pObj = pDict->GetElement("Pg"); + FX_DWORD PageObjNum = 0; + if (CPDF_Reference* pRef = ToReference(pObj)) + PageObjNum = pRef->GetRefObjNum(); + + CPDF_Object* pKids = pDict->GetElementValue("K"); + if (!pKids) + return; + + if (CPDF_Array* pArray = pKids->AsArray()) { + m_Kids.SetSize(pArray->GetCount()); + for (FX_DWORD i = 0; i < pArray->GetCount(); i++) { + CPDF_Object* pKid = pArray->GetElementValue(i); + LoadKid(PageObjNum, pKid, &m_Kids[i]); + } + } else { + m_Kids.SetSize(1); + LoadKid(PageObjNum, pKids, &m_Kids[0]); + } +} +void CPDF_StructElementImpl::LoadKid(FX_DWORD PageObjNum, + CPDF_Object* pKidObj, + CPDF_StructKid* pKid) { + pKid->m_Type = CPDF_StructKid::Invalid; + if (!pKidObj) + return; + + if (pKidObj->IsNumber()) { + if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) { + return; + } + pKid->m_Type = CPDF_StructKid::PageContent; + pKid->m_PageContent.m_ContentId = pKidObj->GetInteger(); + pKid->m_PageContent.m_PageObjNum = PageObjNum; + return; + } + + CPDF_Dictionary* pKidDict = pKidObj->AsDictionary(); + if (!pKidDict) + return; + + if (CPDF_Reference* pRef = ToReference(pKidDict->GetElement("Pg"))) + PageObjNum = pRef->GetRefObjNum(); + + CFX_ByteString type = pKidDict->GetStringBy("Type"); + if (type == "MCR") { + if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) { + return; + } + pKid->m_Type = CPDF_StructKid::StreamContent; + if (CPDF_Reference* pRef = ToReference(pKidDict->GetElement("Stm"))) { + pKid->m_StreamContent.m_RefObjNum = pRef->GetRefObjNum(); + } else { + pKid->m_StreamContent.m_RefObjNum = 0; + } + pKid->m_StreamContent.m_PageObjNum = PageObjNum; + pKid->m_StreamContent.m_ContentId = pKidDict->GetIntegerBy("MCID"); + } else if (type == "OBJR") { + if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) { + return; + } + pKid->m_Type = CPDF_StructKid::Object; + if (CPDF_Reference* pObj = ToReference(pKidDict->GetElement("Obj"))) { + pKid->m_Object.m_RefObjNum = pObj->GetRefObjNum(); + } else { + pKid->m_Object.m_RefObjNum = 0; + } + pKid->m_Object.m_PageObjNum = PageObjNum; + } else { + pKid->m_Type = CPDF_StructKid::Element; + pKid->m_Element.m_pDict = pKidDict; + if (!m_pTree->m_pPage) { + pKid->m_Element.m_pElement = + new CPDF_StructElementImpl(m_pTree, this, pKidDict); + } else { + pKid->m_Element.m_pElement = NULL; + } + } +} +static CPDF_Dictionary* FindAttrDict(CPDF_Object* pAttrs, + const CFX_ByteStringC& owner, + FX_FLOAT nLevel = 0.0F) { + if (nLevel > nMaxRecursion) + return nullptr; + if (!pAttrs) + return nullptr; + + CPDF_Dictionary* pDict = nullptr; + if (pAttrs->IsDictionary()) { + pDict = pAttrs->AsDictionary(); + } else if (CPDF_Stream* pStream = pAttrs->AsStream()) { + pDict = pStream->GetDict(); + } else if (CPDF_Array* pArray = pAttrs->AsArray()) { + for (FX_DWORD i = 0; i < pArray->GetCount(); i++) { + CPDF_Object* pElement = pArray->GetElementValue(i); + pDict = FindAttrDict(pElement, owner, nLevel + 1); + if (pDict) + return pDict; + } + } + if (pDict && pDict->GetStringBy("O") == owner) + return pDict; + return nullptr; +} +CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_BOOL bInheritable, + FX_FLOAT fLevel) { + if (fLevel > nMaxRecursion) { + return NULL; + } + if (bInheritable) { + CPDF_Object* pAttr = GetAttr(owner, name, FALSE); + if (pAttr) { + return pAttr; + } + if (!m_pParent) { + return NULL; + } + return m_pParent->GetAttr(owner, name, TRUE, fLevel + 1); + } + CPDF_Object* pA = m_pDict->GetElementValue("A"); + if (pA) { + CPDF_Dictionary* pAttrDict = FindAttrDict(pA, owner); + if (pAttrDict) { + CPDF_Object* pAttr = pAttrDict->GetElementValue(name); + if (pAttr) { + return pAttr; + } + } + } + CPDF_Object* pC = m_pDict->GetElementValue("C"); + if (!pC) + return nullptr; + + CPDF_Dictionary* pClassMap = m_pTree->m_pTreeRoot->GetDictBy("ClassMap"); + if (!pClassMap) + return nullptr; + + if (CPDF_Array* pArray = pC->AsArray()) { + for (FX_DWORD i = 0; i < pArray->GetCount(); i++) { + CFX_ByteString class_name = pArray->GetStringAt(i); + CPDF_Dictionary* pClassDict = pClassMap->GetDictBy(class_name); + if (pClassDict && pClassDict->GetStringBy("O") == owner) + return pClassDict->GetElementValue(name); + } + return nullptr; + } + CFX_ByteString class_name = pC->GetString(); + CPDF_Dictionary* pClassDict = pClassMap->GetDictBy(class_name); + if (pClassDict && pClassDict->GetStringBy("O") == owner) + return pClassDict->GetElementValue(name); + return nullptr; +} +CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_BOOL bInheritable, + int subindex) { + CPDF_Object* pAttr = GetAttr(owner, name, bInheritable); + CPDF_Array* pArray = ToArray(pAttr); + if (!pArray || subindex == -1) + return pAttr; + + if (subindex >= static_cast<int>(pArray->GetCount())) + return pAttr; + return pArray->GetElementValue(subindex); +} +CFX_ByteString CPDF_StructElementImpl::GetName( + const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + const CFX_ByteStringC& default_value, + FX_BOOL bInheritable, + int subindex) { + CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex); + if (ToName(pAttr)) + return pAttr->GetString(); + return default_value; +} + +FX_ARGB CPDF_StructElementImpl::GetColor(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_ARGB default_value, + FX_BOOL bInheritable, + int subindex) { + CPDF_Array* pArray = ToArray(GetAttr(owner, name, bInheritable, subindex)); + if (!pArray) + return default_value; + return 0xff000000 | ((int)(pArray->GetNumberAt(0) * 255) << 16) | + ((int)(pArray->GetNumberAt(1) * 255) << 8) | + (int)(pArray->GetNumberAt(2) * 255); +} +FX_FLOAT CPDF_StructElementImpl::GetNumber(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_FLOAT default_value, + FX_BOOL bInheritable, + int subindex) { + CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex); + return ToNumber(pAttr) ? pAttr->GetNumber() : default_value; +} +int CPDF_StructElementImpl::GetInteger(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + int default_value, + FX_BOOL bInheritable, + int subindex) { + CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex); + return ToNumber(pAttr) ? pAttr->GetInteger() : default_value; +} diff --git a/core/fpdfdoc/doc_utils.cpp b/core/fpdfdoc/doc_utils.cpp new file mode 100644 index 0000000000..5160c1115c --- /dev/null +++ b/core/fpdfdoc/doc_utils.cpp @@ -0,0 +1,753 @@ +// 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 <algorithm> +#include <vector> + +#include "core/fpdfdoc/doc_utils.h" +#include "core/include/fpdfapi/cpdf_array.h" +#include "core/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfapi/cpdf_simple_parser.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +namespace { + +const int FPDFDOC_UTILS_MAXRECURSION = 32; + +CPDF_Object* SearchNumberNode(const CPDF_Dictionary* pNode, int num) { + CPDF_Array* pLimits = pNode->GetArrayBy("Limits"); + if (pLimits && + (num < pLimits->GetIntegerAt(0) || num > pLimits->GetIntegerAt(1))) { + return NULL; + } + CPDF_Array* pNumbers = pNode->GetArrayBy("Nums"); + if (pNumbers) { + FX_DWORD dwCount = pNumbers->GetCount() / 2; + for (FX_DWORD i = 0; i < dwCount; i++) { + int index = pNumbers->GetIntegerAt(i * 2); + if (num == index) { + return pNumbers->GetElementValue(i * 2 + 1); + } + if (index > num) { + break; + } + } + return NULL; + } + CPDF_Array* pKids = pNode->GetArrayBy("Kids"); + if (!pKids) { + return NULL; + } + for (FX_DWORD i = 0; i < pKids->GetCount(); i++) { + CPDF_Dictionary* pKid = pKids->GetDictAt(i); + if (!pKid) { + continue; + } + CPDF_Object* pFound = SearchNumberNode(pKid, num); + if (pFound) { + return pFound; + } + } + return NULL; +} + +} // namespace + +CPDF_Object* CPDF_NumberTree::LookupValue(int num) const { + return SearchNumberNode(m_pRoot, num); +} + +CFX_WideString GetFullName(CPDF_Dictionary* pFieldDict) { + CFX_WideString full_name; + CPDF_Dictionary* pLevel = pFieldDict; + while (pLevel) { + CFX_WideString short_name = pLevel->GetUnicodeTextBy("T"); + if (short_name != L"") { + if (full_name == L"") { + full_name = short_name; + } else { + full_name = short_name + L"." + full_name; + } + } + pLevel = pLevel->GetDictBy("Parent"); + } + return full_name; +} +FX_BOOL CPDF_DefaultAppearance::HasFont() { + if (m_csDA.IsEmpty()) { + return FALSE; + } + CPDF_SimpleParser syntax(m_csDA); + return syntax.FindTagParamFromStart("Tf", 2); +} +CFX_ByteString CPDF_DefaultAppearance::GetFontString() { + CFX_ByteString csFont; + if (m_csDA.IsEmpty()) { + return csFont; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart("Tf", 2)) { + csFont += (CFX_ByteString)syntax.GetWord(); + csFont += " "; + csFont += (CFX_ByteString)syntax.GetWord(); + csFont += " "; + csFont += (CFX_ByteString)syntax.GetWord(); + } + return csFont; +} +void CPDF_DefaultAppearance::GetFont(CFX_ByteString& csFontNameTag, + FX_FLOAT& fFontSize) { + csFontNameTag = ""; + fFontSize = 0; + if (m_csDA.IsEmpty()) { + return; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart("Tf", 2)) { + csFontNameTag = (CFX_ByteString)syntax.GetWord(); + csFontNameTag.Delete(0, 1); + fFontSize = FX_atof((CFX_ByteString)syntax.GetWord()); + } + csFontNameTag = PDF_NameDecode(csFontNameTag); +} +FX_BOOL CPDF_DefaultAppearance::HasColor(FX_BOOL bStrokingOperation) { + if (m_csDA.IsEmpty()) { + return FALSE; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { + return TRUE; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { + return TRUE; + } + return syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4); +} +CFX_ByteString CPDF_DefaultAppearance::GetColorString( + FX_BOOL bStrokingOperation) { + CFX_ByteString csColor; + if (m_csDA.IsEmpty()) { + return csColor; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + return csColor; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + return csColor; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4)) { + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + csColor += " "; + csColor += (CFX_ByteString)syntax.GetWord(); + } + return csColor; +} +void CPDF_DefaultAppearance::GetColor(int& iColorType, + FX_FLOAT fc[4], + FX_BOOL bStrokingOperation) { + iColorType = COLORTYPE_TRANSPARENT; + for (int c = 0; c < 4; c++) { + fc[c] = 0; + } + if (m_csDA.IsEmpty()) { + return; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { + iColorType = COLORTYPE_GRAY; + fc[0] = FX_atof((CFX_ByteString)syntax.GetWord()); + return; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { + iColorType = COLORTYPE_RGB; + fc[0] = FX_atof((CFX_ByteString)syntax.GetWord()); + fc[1] = FX_atof((CFX_ByteString)syntax.GetWord()); + fc[2] = FX_atof((CFX_ByteString)syntax.GetWord()); + return; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4)) { + iColorType = COLORTYPE_CMYK; + fc[0] = FX_atof((CFX_ByteString)syntax.GetWord()); + fc[1] = FX_atof((CFX_ByteString)syntax.GetWord()); + fc[2] = FX_atof((CFX_ByteString)syntax.GetWord()); + fc[3] = FX_atof((CFX_ByteString)syntax.GetWord()); + } +} +void CPDF_DefaultAppearance::GetColor(FX_ARGB& color, + int& iColorType, + FX_BOOL bStrokingOperation) { + color = 0; + iColorType = COLORTYPE_TRANSPARENT; + if (m_csDA.IsEmpty()) { + return; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { + iColorType = COLORTYPE_GRAY; + FX_FLOAT g = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f; + color = ArgbEncode(255, (int)g, (int)g, (int)g); + return; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { + iColorType = COLORTYPE_RGB; + FX_FLOAT r = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f; + FX_FLOAT g = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f; + FX_FLOAT b = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f; + color = ArgbEncode(255, (int)r, (int)g, (int)b); + return; + } + if (syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4)) { + iColorType = COLORTYPE_CMYK; + FX_FLOAT c = FX_atof((CFX_ByteString)syntax.GetWord()); + FX_FLOAT m = FX_atof((CFX_ByteString)syntax.GetWord()); + FX_FLOAT y = FX_atof((CFX_ByteString)syntax.GetWord()); + FX_FLOAT k = FX_atof((CFX_ByteString)syntax.GetWord()); + FX_FLOAT r = 1.0f - std::min(1.0f, c + k); + FX_FLOAT g = 1.0f - std::min(1.0f, m + k); + FX_FLOAT b = 1.0f - std::min(1.0f, y + k); + color = ArgbEncode(255, (int)(r * 255 + 0.5f), (int)(g * 255 + 0.5f), + (int)(b * 255 + 0.5f)); + } +} +FX_BOOL CPDF_DefaultAppearance::HasTextMatrix() { + if (m_csDA.IsEmpty()) { + return FALSE; + } + CPDF_SimpleParser syntax(m_csDA); + return syntax.FindTagParamFromStart("Tm", 6); +} +CFX_ByteString CPDF_DefaultAppearance::GetTextMatrixString() { + CFX_ByteString csTM; + if (m_csDA.IsEmpty()) { + return csTM; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart("Tm", 6)) { + for (int i = 0; i < 6; i++) { + csTM += (CFX_ByteString)syntax.GetWord(); + csTM += " "; + } + csTM += (CFX_ByteString)syntax.GetWord(); + } + return csTM; +} +CFX_Matrix CPDF_DefaultAppearance::GetTextMatrix() { + CFX_Matrix tm; + if (m_csDA.IsEmpty()) { + return tm; + } + CPDF_SimpleParser syntax(m_csDA); + if (syntax.FindTagParamFromStart("Tm", 6)) { + FX_FLOAT f[6]; + for (int i = 0; i < 6; i++) { + f[i] = FX_atof((CFX_ByteString)syntax.GetWord()); + } + tm.Set(f[0], f[1], f[2], f[3], f[4], f[5]); + } + return tm; +} +void InitInterFormDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) { + if (!pDocument) { + return; + } + if (!pFormDict) { + pFormDict = new CPDF_Dictionary; + FX_DWORD dwObjNum = pDocument->AddIndirectObject(pFormDict); + CPDF_Dictionary* pRoot = pDocument->GetRoot(); + pRoot->SetAtReference("AcroForm", pDocument, dwObjNum); + } + CFX_ByteString csDA; + if (!pFormDict->KeyExist("DR")) { + CPDF_Font* pFont = NULL; + CFX_ByteString csBaseName, csDefault; + uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); + pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica"); + if (pFont) { + AddInterFormFont(pFormDict, pDocument, pFont, csBaseName); + csDefault = csBaseName; + } + if (charSet != 0) { + CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, NULL); + if (!pFont || csFontName != "Helvetica") { + pFont = CPDF_InterForm::AddNativeFont(pDocument); + if (pFont) { + csBaseName = ""; + AddInterFormFont(pFormDict, pDocument, pFont, csBaseName); + csDefault = csBaseName; + } + } + } + if (pFont) { + csDA = "/" + PDF_NameEncode(csDefault) + " 0 Tf"; + } + } + if (!csDA.IsEmpty()) { + csDA += " "; + } + csDA += "0 g"; + if (!pFormDict->KeyExist("DA")) { + pFormDict->SetAtString("DA", csDA); + } +} +FX_DWORD CountInterFormFonts(CPDF_Dictionary* pFormDict) { + if (!pFormDict) { + return 0; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return 0; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return 0; + } + FX_DWORD dwCount = 0; + for (const auto& it : *pFonts) { + CPDF_Object* pObj = it.second; + if (!pObj) { + continue; + } + if (CPDF_Dictionary* pDirect = ToDictionary(pObj->GetDirect())) { + if (pDirect->GetStringBy("Type") == "Font") { + dwCount++; + } + } + } + return dwCount; +} +CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + FX_DWORD index, + CFX_ByteString& csNameTag) { + if (!pFormDict) { + return NULL; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return NULL; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return NULL; + } + FX_DWORD dwCount = 0; + for (const auto& it : *pFonts) { + const CFX_ByteString& csKey = it.first; + CPDF_Object* pObj = it.second; + if (!pObj) { + continue; + } + CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); + if (!pElement) + continue; + if (pElement->GetStringBy("Type") != "Font") + continue; + if (dwCount == index) { + csNameTag = csKey; + return pDocument->LoadFont(pElement); + } + dwCount++; + } + return NULL; +} +CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString csNameTag) { + CFX_ByteString csAlias = PDF_NameDecode(csNameTag); + if (!pFormDict || csAlias.IsEmpty()) { + return NULL; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return NULL; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return NULL; + } + CPDF_Dictionary* pElement = pFonts->GetDictBy(csAlias); + if (!pElement) { + return NULL; + } + if (pElement->GetStringBy("Type") == "Font") { + return pDocument->LoadFont(pElement); + } + return NULL; +} +CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString csFontName, + CFX_ByteString& csNameTag) { + if (!pFormDict || csFontName.IsEmpty()) { + return NULL; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return NULL; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return NULL; + } + for (const auto& it : *pFonts) { + const CFX_ByteString& csKey = it.first; + CPDF_Object* pObj = it.second; + if (!pObj) { + continue; + } + CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); + if (!pElement) + continue; + if (pElement->GetStringBy("Type") != "Font") + continue; + + CPDF_Font* pFind = pDocument->LoadFont(pElement); + if (!pFind) + continue; + + CFX_ByteString csBaseFont; + csBaseFont = pFind->GetBaseFont(); + csBaseFont.Remove(' '); + if (csBaseFont == csFontName) { + csNameTag = csKey; + return pFind; + } + } + return NULL; +} +CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + uint8_t charSet, + CFX_ByteString& csNameTag) { + if (!pFormDict) { + return NULL; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return NULL; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return NULL; + } + for (const auto& it : *pFonts) { + const CFX_ByteString& csKey = it.first; + CPDF_Object* pObj = it.second; + if (!pObj) { + continue; + } + CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); + if (!pElement) + continue; + if (pElement->GetStringBy("Type") != "Font") + continue; + CPDF_Font* pFind = pDocument->LoadFont(pElement); + if (!pFind) { + continue; + } + CFX_SubstFont* pSubst = (CFX_SubstFont*)pFind->GetSubstFont(); + if (!pSubst) { + continue; + } + if (pSubst->m_Charset == (int)charSet) { + csNameTag = csKey; + return pFind; + } + } + return NULL; +} +CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString& csNameTag) { + csNameTag = ""; + uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); + CFX_SubstFont* pSubst; + CPDF_Font* pFont = GetDefaultInterFormFont(pFormDict, pDocument); + if (pFont) { + pSubst = (CFX_SubstFont*)pFont->GetSubstFont(); + if (pSubst && pSubst->m_Charset == (int)charSet) { + FindInterFormFont(pFormDict, pFont, csNameTag); + return pFont; + } + } + return GetNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag); +} +FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, + const CPDF_Font* pFont, + CFX_ByteString& csNameTag) { + if (!pFormDict || !pFont) { + return FALSE; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return FALSE; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return FALSE; + } + for (const auto& it : *pFonts) { + const CFX_ByteString& csKey = it.first; + CPDF_Object* pObj = it.second; + if (!pObj) { + continue; + } + CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); + if (!pElement) + continue; + if (pElement->GetStringBy("Type") != "Font") { + continue; + } + if (pFont->GetFontDict() == pElement) { + csNameTag = csKey; + return TRUE; + } + } + return FALSE; +} +FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString csFontName, + CPDF_Font*& pFont, + CFX_ByteString& csNameTag) { + if (!pFormDict) { + return FALSE; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return FALSE; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return FALSE; + } + if (csFontName.GetLength() > 0) { + csFontName.Remove(' '); + } + for (const auto& it : *pFonts) { + const CFX_ByteString& csKey = it.first; + CPDF_Object* pObj = it.second; + if (!pObj) { + continue; + } + CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); + if (!pElement) + continue; + if (pElement->GetStringBy("Type") != "Font") { + continue; + } + pFont = pDocument->LoadFont(pElement); + if (!pFont) { + continue; + } + CFX_ByteString csBaseFont; + csBaseFont = pFont->GetBaseFont(); + csBaseFont.Remove(' '); + if (csBaseFont == csFontName) { + csNameTag = csKey; + return TRUE; + } + } + return FALSE; +} +void AddInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + const CPDF_Font* pFont, + CFX_ByteString& csNameTag) { + if (!pFont) { + return; + } + if (!pFormDict) { + InitInterFormDict(pFormDict, pDocument); + } + CFX_ByteString csTag; + if (FindInterFormFont(pFormDict, pFont, csTag)) { + csNameTag = csTag; + return; + } + if (!pFormDict) { + InitInterFormDict(pFormDict, pDocument); + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + pDR = new CPDF_Dictionary; + pFormDict->SetAt("DR", pDR); + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + pFonts = new CPDF_Dictionary; + pDR->SetAt("Font", pFonts); + } + if (csNameTag.IsEmpty()) { + csNameTag = pFont->GetBaseFont(); + } + csNameTag.Remove(' '); + csNameTag = + CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4, csNameTag); + pFonts->SetAtReference(csNameTag, pDocument, pFont->GetFontDict()); +} +CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + uint8_t charSet, + CFX_ByteString& csNameTag) { + if (!pFormDict) { + InitInterFormDict(pFormDict, pDocument); + } + CFX_ByteString csTemp; + CPDF_Font* pFont = + GetNativeInterFormFont(pFormDict, pDocument, charSet, csTemp); + if (pFont) { + csNameTag = csTemp; + return pFont; + } + CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet); + if (!csFontName.IsEmpty()) { + if (FindInterFormFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) { + return pFont; + } + } + pFont = CPDF_InterForm::AddNativeFont(charSet, pDocument); + if (pFont) { + AddInterFormFont(pFormDict, pDocument, pFont, csNameTag); + } + return pFont; +} +CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + CFX_ByteString& csNameTag) { + uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); + return AddNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag); +} +void RemoveInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont) { + if (!pFormDict || !pFont) { + return; + } + CFX_ByteString csTag; + if (!FindInterFormFont(pFormDict, pFont, csTag)) { + return; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + pFonts->RemoveAt(csTag); +} +void RemoveInterFormFont(CPDF_Dictionary* pFormDict, CFX_ByteString csNameTag) { + if (!pFormDict || csNameTag.IsEmpty()) { + return; + } + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) { + return; + } + CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); + if (!pFonts) { + return; + } + pFonts->RemoveAt(csNameTag); +} + +CPDF_Font* GetDefaultInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument) { + if (!pFormDict) { + return NULL; + } + CPDF_DefaultAppearance cDA(pFormDict->GetStringBy("DA")); + CFX_ByteString csFontNameTag; + FX_FLOAT fFontSize; + cDA.GetFont(csFontNameTag, fFontSize); + return GetInterFormFont(pFormDict, pDocument, csFontNameTag); +} + +CPDF_IconFit::ScaleMethod CPDF_IconFit::GetScaleMethod() { + if (!m_pDict) { + return Always; + } + CFX_ByteString csSW = m_pDict->GetStringBy("SW", "A"); + if (csSW == "B") { + return Bigger; + } + if (csSW == "S") { + return Smaller; + } + if (csSW == "N") { + return Never; + } + return Always; +} +FX_BOOL CPDF_IconFit::IsProportionalScale() { + if (!m_pDict) { + return TRUE; + } + return m_pDict->GetStringBy("S", "P") != "A"; +} +void CPDF_IconFit::GetIconPosition(FX_FLOAT& fLeft, FX_FLOAT& fBottom) { + fLeft = fBottom = 0.5; + if (!m_pDict) { + return; + } + CPDF_Array* pA = m_pDict->GetArrayBy("A"); + if (pA) { + FX_DWORD dwCount = pA->GetCount(); + if (dwCount > 0) { + fLeft = pA->GetNumberAt(0); + } + if (dwCount > 1) { + fBottom = pA->GetNumberAt(1); + } + } +} +FX_BOOL CPDF_IconFit::GetFittingBounds() { + if (!m_pDict) { + return FALSE; + } + return m_pDict->GetBooleanBy("FB"); +} + +std::vector<bool> SaveCheckedFieldStatus(CPDF_FormField* pField) { + std::vector<bool> result; + int iCount = pField->CountControls(); + for (int i = 0; i < iCount; ++i) { + if (CPDF_FormControl* pControl = pField->GetControl(i)) + result.push_back(pControl->IsChecked()); + } + return result; +} + +CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict, + const FX_CHAR* name, + int nLevel) { + if (nLevel > FPDFDOC_UTILS_MAXRECURSION) { + return NULL; + } + if (!pFieldDict) { + return NULL; + } + CPDF_Object* pAttr = pFieldDict->GetElementValue(name); + if (pAttr) { + return pAttr; + } + CPDF_Dictionary* pParent = pFieldDict->GetDictBy("Parent"); + if (!pParent) { + return NULL; + } + return FPDF_GetFieldAttr(pParent, name, nLevel + 1); +} diff --git a/core/fpdfdoc/doc_utils.h b/core/fpdfdoc/doc_utils.h new file mode 100644 index 0000000000..ed687943da --- /dev/null +++ b/core/fpdfdoc/doc_utils.h @@ -0,0 +1,80 @@ +// Copyright 2015 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 + +#ifndef CORE_FPDFDOC_DOC_UTILS_H_ +#define CORE_FPDFDOC_DOC_UTILS_H_ + +#include <vector> + +#include "core/include/fpdfapi/cpdf_parser.h" +#include "core/include/fpdfapi/fpdf_resource.h" + +class CPDF_Dictionary; +class CPDF_FormField; + +class CPDF_NumberTree { + public: + CPDF_NumberTree(CPDF_Dictionary* pRoot) : m_pRoot(pRoot) {} + CPDF_Object* LookupValue(int num) const; + + protected: + CPDF_Dictionary* const m_pRoot; +}; + +CFX_WideString GetFullName(CPDF_Dictionary* pFieldDict); +void InitInterFormDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument); +FX_DWORD CountInterFormFonts(CPDF_Dictionary* pFormDict); +CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + FX_DWORD index, + CFX_ByteString& csNameTag); +CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString csNameTag); +CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString csFontName, + CFX_ByteString& csNameTag); +CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + uint8_t charSet, + CFX_ByteString& csNameTag); +CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString& csNameTag); +FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, + const CPDF_Font* pFont, + CFX_ByteString& csNameTag); +FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + CFX_ByteString csFontName, + CPDF_Font*& pFont, + CFX_ByteString& csNameTag); +void AddInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + const CPDF_Font* pFont, + CFX_ByteString& csNameTag); +CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + uint8_t charSet, + CFX_ByteString& csNameTag); +CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + CFX_ByteString& csNameTag); +void RemoveInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont); +void RemoveInterFormFont(CPDF_Dictionary* pFormDict, CFX_ByteString csNameTag); +CPDF_Font* GetDefaultInterFormFont(CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument); +void SetDefaultInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + const CPDF_Font* pFont); +std::vector<bool> SaveCheckedFieldStatus(CPDF_FormField* pField); +FX_BOOL NeedPDFEncodeForFieldFullName(const CFX_WideString& csFieldName); +FX_BOOL NeedPDFEncodeForFieldTree(CPDF_Dictionary* pFieldDict, int nLevel = 0); +void EncodeFieldName(const CFX_WideString& csName, CFX_ByteString& csT); +void UpdateEncodeFieldName(CPDF_Dictionary* pFieldDict, int nLevel = 0); + +#endif // CORE_FPDFDOC_DOC_UTILS_H_ diff --git a/core/fpdfdoc/doc_viewerPreferences.cpp b/core/fpdfdoc/doc_viewerPreferences.cpp new file mode 100644 index 0000000000..582f3a5a93 --- /dev/null +++ b/core/fpdfdoc/doc_viewerPreferences.cpp @@ -0,0 +1,54 @@ +// 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/include/fpdfapi/cpdf_document.h" +#include "core/include/fpdfdoc/fpdf_doc.h" + +CPDF_ViewerPreferences::CPDF_ViewerPreferences(CPDF_Document* pDoc) + : m_pDoc(pDoc) {} +CPDF_ViewerPreferences::~CPDF_ViewerPreferences() {} +FX_BOOL CPDF_ViewerPreferences::IsDirectionR2L() const { + CPDF_Dictionary* pDict = m_pDoc->GetRoot(); + pDict = pDict->GetDictBy("ViewerPreferences"); + if (!pDict) { + return FALSE; + } + return "R2L" == pDict->GetStringBy("Direction"); +} +FX_BOOL CPDF_ViewerPreferences::PrintScaling() const { + CPDF_Dictionary* pDict = m_pDoc->GetRoot(); + pDict = pDict->GetDictBy("ViewerPreferences"); + if (!pDict) { + return TRUE; + } + return "None" != pDict->GetStringBy("PrintScaling"); +} +int32_t CPDF_ViewerPreferences::NumCopies() const { + CPDF_Dictionary* pDict = m_pDoc->GetRoot(); + pDict = pDict->GetDictBy("ViewerPreferences"); + if (!pDict) { + return 1; + } + return pDict->GetIntegerBy("NumCopies"); +} +CPDF_Array* CPDF_ViewerPreferences::PrintPageRange() const { + CPDF_Dictionary* pDict = m_pDoc->GetRoot(); + CPDF_Array* pRange = NULL; + pDict = pDict->GetDictBy("ViewerPreferences"); + if (!pDict) { + return pRange; + } + pRange = pDict->GetArrayBy("PrintPageRange"); + return pRange; +} +CFX_ByteString CPDF_ViewerPreferences::Duplex() const { + CPDF_Dictionary* pDict = m_pDoc->GetRoot(); + pDict = pDict->GetDictBy("ViewerPreferences"); + if (!pDict) { + return "None"; + } + return pDict->GetStringBy("Duplex"); +} diff --git a/core/fpdfdoc/doc_vt.cpp b/core/fpdfdoc/doc_vt.cpp new file mode 100644 index 0000000000..dddc57f2dd --- /dev/null +++ b/core/fpdfdoc/doc_vt.cpp @@ -0,0 +1,1825 @@ +// 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 <algorithm> + +#include "core/fpdfdoc/pdf_vt.h" +#include "core/include/fpdfdoc/fpdf_doc.h" +#include "core/include/fpdfdoc/fpdf_vt.h" + +const uint8_t gFontSizeSteps[] = {4, 6, 8, 9, 10, 12, 14, 18, 20, + 25, 30, 35, 40, 45, 50, 55, 60, 70, + 80, 90, 100, 110, 120, 130, 144}; +#define PVT_RETURN_LENGTH 1 +#define PVT_DEFAULT_FONTSIZE 18.0f +#define PVTWORD_SCRIPT_NORMAL 0 +#define PVTWORD_SCRIPT_SUPER 1 +#define PVTWORD_SCRIPT_SUB 2 +#define PVT_FONTSCALE 0.001f +#define PVT_PERCENT 0.01f +#define PVT_HALF 0.5f +CLine::CLine() {} +CLine::~CLine() {} +CPVT_WordPlace CLine::GetBeginWordPlace() const { + return CPVT_WordPlace(LinePlace.nSecIndex, LinePlace.nLineIndex, -1); +} +CPVT_WordPlace CLine::GetEndWordPlace() const { + return CPVT_WordPlace(LinePlace.nSecIndex, LinePlace.nLineIndex, + m_LineInfo.nEndWordIndex); +} +CPVT_WordPlace CLine::GetPrevWordPlace(const CPVT_WordPlace& place) const { + if (place.nWordIndex > m_LineInfo.nEndWordIndex) { + return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, + m_LineInfo.nEndWordIndex); + } + return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, + place.nWordIndex - 1); +} +CPVT_WordPlace CLine::GetNextWordPlace(const CPVT_WordPlace& place) const { + if (place.nWordIndex < m_LineInfo.nBeginWordIndex) { + return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, + m_LineInfo.nBeginWordIndex); + } + return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, + place.nWordIndex + 1); +} +CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {} +CSection::~CSection() { + ResetAll(); +} +void CSection::ResetAll() { + ResetWordArray(); + ResetLineArray(); +} +void CSection::ResetLineArray() { + m_LineArray.RemoveAll(); +} +void CSection::ResetWordArray() { + for (int32_t i = 0, sz = m_WordArray.GetSize(); i < sz; i++) { + delete m_WordArray.GetAt(i); + } + m_WordArray.RemoveAll(); +} +void CSection::ResetLinePlace() { + for (int32_t i = 0, sz = m_LineArray.GetSize(); i < sz; i++) { + if (CLine* pLine = m_LineArray.GetAt(i)) { + pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1); + } + } +} +CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place, + const CPVT_WordInfo& wordinfo) { + CPVT_WordInfo* pWord = new CPVT_WordInfo(wordinfo); + int32_t nWordIndex = + std::max(std::min(place.nWordIndex, m_WordArray.GetSize()), 0); + if (nWordIndex == m_WordArray.GetSize()) { + m_WordArray.Add(pWord); + } else { + m_WordArray.InsertAt(nWordIndex, pWord); + } + return place; +} +CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo& lineinfo) { + return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.Add(lineinfo), -1); +} +CPVT_FloatRect CSection::Rearrange() { + if (m_pVT->m_nCharArray > 0) { + return CTypeset(this).CharArray(); + } + return CTypeset(this).Typeset(); +} +CPVT_Size CSection::GetSectionSize(FX_FLOAT fFontSize) { + return CTypeset(this).GetEditSize(fFontSize); +} +CPVT_WordPlace CSection::GetBeginWordPlace() const { + if (CLine* pLine = m_LineArray.GetAt(0)) { + return pLine->GetBeginWordPlace(); + } + return SecPlace; +} +CPVT_WordPlace CSection::GetEndWordPlace() const { + if (CLine* pLine = m_LineArray.GetAt(m_LineArray.GetSize() - 1)) { + return pLine->GetEndWordPlace(); + } + return SecPlace; +} +CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace& place) const { + if (place.nLineIndex < 0) { + return GetBeginWordPlace(); + } + if (place.nLineIndex >= m_LineArray.GetSize()) { + return GetEndWordPlace(); + } + if (CLine* pLine = m_LineArray.GetAt(place.nLineIndex)) { + if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex) { + return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1); + } + if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) { + if (CLine* pPrevLine = m_LineArray.GetAt(place.nLineIndex - 1)) { + return pPrevLine->GetEndWordPlace(); + } + } else { + return pLine->GetPrevWordPlace(place); + } + } + return place; +} +CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace& place) const { + if (place.nLineIndex < 0) { + return GetBeginWordPlace(); + } + if (place.nLineIndex >= m_LineArray.GetSize()) { + return GetEndWordPlace(); + } + if (CLine* pLine = m_LineArray.GetAt(place.nLineIndex)) { + if (place.nWordIndex >= pLine->m_LineInfo.nEndWordIndex) { + if (CLine* pNextLine = m_LineArray.GetAt(place.nLineIndex + 1)) { + return pNextLine->GetBeginWordPlace(); + } + } else { + return pLine->GetNextWordPlace(place); + } + } + return place; +} +void CSection::UpdateWordPlace(CPVT_WordPlace& place) const { + int32_t nLeft = 0; + int32_t nRight = m_LineArray.GetSize() - 1; + int32_t nMid = (nLeft + nRight) / 2; + while (nLeft <= nRight) { + if (CLine* pLine = m_LineArray.GetAt(nMid)) { + if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) { + nRight = nMid - 1; + nMid = (nLeft + nRight) / 2; + } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) { + nLeft = nMid + 1; + nMid = (nLeft + nRight) / 2; + } else { + place.nLineIndex = nMid; + return; + } + } else { + break; + } + } +} +CPVT_WordPlace CSection::SearchWordPlace(const CFX_FloatPoint& point) const { + ASSERT(m_pVT); + CPVT_WordPlace place = GetBeginWordPlace(); + FX_BOOL bUp = TRUE; + FX_BOOL bDown = TRUE; + int32_t nLeft = 0; + int32_t nRight = m_LineArray.GetSize() - 1; + int32_t nMid = m_LineArray.GetSize() / 2; + FX_FLOAT fTop = 0; + FX_FLOAT fBottom = 0; + while (nLeft <= nRight) { + if (CLine* pLine = m_LineArray.GetAt(nMid)) { + fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent - + m_pVT->GetLineLeading(m_SecInfo); + fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent; + if (IsFloatBigger(point.y, fTop)) { + bUp = FALSE; + } + if (IsFloatSmaller(point.y, fBottom)) { + bDown = FALSE; + } + if (IsFloatSmaller(point.y, fTop)) { + nRight = nMid - 1; + nMid = (nLeft + nRight) / 2; + continue; + } else if (IsFloatBigger(point.y, fBottom)) { + nLeft = nMid + 1; + nMid = (nLeft + nRight) / 2; + continue; + } else { + place = SearchWordPlace( + point.x, + CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()), + pLine->GetEndWordPlace())); + place.nLineIndex = nMid; + return place; + } + } + } + if (bUp) { + place = GetBeginWordPlace(); + } + if (bDown) { + place = GetEndWordPlace(); + } + return place; +} +CPVT_WordPlace CSection::SearchWordPlace( + FX_FLOAT fx, + const CPVT_WordPlace& lineplace) const { + if (CLine* pLine = m_LineArray.GetAt(lineplace.nLineIndex)) { + return SearchWordPlace( + fx - m_SecInfo.rcSection.left, + CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()), + pLine->GetEndWordPlace())); + } + return GetBeginWordPlace(); +} +CPVT_WordPlace CSection::SearchWordPlace(FX_FLOAT fx, + const CPVT_WordRange& range) const { + CPVT_WordPlace wordplace = range.BeginPos; + wordplace.nWordIndex = -1; + if (!m_pVT) { + return wordplace; + } + int32_t nLeft = range.BeginPos.nWordIndex; + int32_t nRight = range.EndPos.nWordIndex + 1; + int32_t nMid = (nLeft + nRight) / 2; + while (nLeft < nRight) { + if (nMid == nLeft) { + break; + } + if (nMid == nRight) { + nMid--; + break; + } + if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) { + if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * PVT_HALF) { + nLeft = nMid; + nMid = (nLeft + nRight) / 2; + continue; + } else { + nRight = nMid; + nMid = (nLeft + nRight) / 2; + continue; + } + } else { + break; + } + } + if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) { + if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * PVT_HALF) { + wordplace.nWordIndex = nMid; + } + } + return wordplace; +} +void CSection::ClearLeftWords(int32_t nWordIndex) { + for (int32_t i = nWordIndex; i >= 0; i--) { + delete m_WordArray.GetAt(i); + m_WordArray.RemoveAt(i); + } +} +void CSection::ClearRightWords(int32_t nWordIndex) { + for (int32_t i = m_WordArray.GetSize() - 1; i > nWordIndex; i--) { + delete m_WordArray.GetAt(i); + m_WordArray.RemoveAt(i); + } +} +void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) { + for (int32_t i = nEndIndex; i > nBeginIndex; i--) { + delete m_WordArray.GetAt(i); + m_WordArray.RemoveAt(i); + } +} +void CSection::ClearWords(const CPVT_WordRange& PlaceRange) { + CPVT_WordPlace SecBeginPos = GetBeginWordPlace(); + CPVT_WordPlace SecEndPos = GetEndWordPlace(); + if (PlaceRange.BeginPos.WordCmp(SecBeginPos) >= 0) { + if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) { + ClearMidWords(PlaceRange.BeginPos.nWordIndex, + PlaceRange.EndPos.nWordIndex); + } else { + ClearRightWords(PlaceRange.BeginPos.nWordIndex); + } + } else if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) { + ClearLeftWords(PlaceRange.EndPos.nWordIndex); + } else { + ResetWordArray(); + } +} +void CSection::ClearWord(const CPVT_WordPlace& place) { + delete m_WordArray.GetAt(place.nWordIndex); + m_WordArray.RemoveAt(place.nWordIndex); +} +CTypeset::CTypeset(CSection* pSection) + : m_rcRet(0.0f, 0.0f, 0.0f, 0.0f), + m_pVT(pSection->m_pVT), + m_pSection(pSection) {} +CTypeset::~CTypeset() {} +CPVT_FloatRect CTypeset::CharArray() { + ASSERT(m_pSection); + FX_FLOAT fLineAscent = + m_pVT->GetFontAscent(m_pVT->GetDefaultFontIndex(), m_pVT->GetFontSize()); + FX_FLOAT fLineDescent = + m_pVT->GetFontDescent(m_pVT->GetDefaultFontIndex(), m_pVT->GetFontSize()); + m_rcRet.Default(); + FX_FLOAT x = 0.0f, y = 0.0f; + FX_FLOAT fNextWidth; + int32_t nStart = 0; + FX_FLOAT fNodeWidth = m_pVT->GetPlateWidth() / + (m_pVT->m_nCharArray <= 0 ? 1 : m_pVT->m_nCharArray); + if (CLine* pLine = m_pSection->m_LineArray.GetAt(0)) { + x = 0.0f; + y += m_pVT->GetLineLeading(m_pSection->m_SecInfo); + y += fLineAscent; + nStart = 0; + switch (m_pVT->GetAlignment(m_pSection->m_SecInfo)) { + case 0: + pLine->m_LineInfo.fLineX = fNodeWidth * PVT_HALF; + break; + case 1: + nStart = (m_pVT->m_nCharArray - m_pSection->m_WordArray.GetSize()) / 2; + pLine->m_LineInfo.fLineX = fNodeWidth * nStart - fNodeWidth * PVT_HALF; + break; + case 2: + nStart = m_pVT->m_nCharArray - m_pSection->m_WordArray.GetSize(); + pLine->m_LineInfo.fLineX = fNodeWidth * nStart - fNodeWidth * PVT_HALF; + break; + } + for (int32_t w = 0, sz = m_pSection->m_WordArray.GetSize(); w < sz; w++) { + if (w >= m_pVT->m_nCharArray) { + break; + } + fNextWidth = 0; + if (CPVT_WordInfo* pNextWord = + (CPVT_WordInfo*)m_pSection->m_WordArray.GetAt(w + 1)) { + pNextWord->fWordTail = 0; + fNextWidth = m_pVT->GetWordWidth(*pNextWord); + } + if (CPVT_WordInfo* pWord = + (CPVT_WordInfo*)m_pSection->m_WordArray.GetAt(w)) { + pWord->fWordTail = 0; + FX_FLOAT fWordWidth = m_pVT->GetWordWidth(*pWord); + FX_FLOAT fWordAscent = m_pVT->GetWordAscent(*pWord); + FX_FLOAT fWordDescent = m_pVT->GetWordDescent(*pWord); + x = (FX_FLOAT)(fNodeWidth * (w + nStart + 0.5) - fWordWidth * PVT_HALF); + pWord->fWordX = x; + pWord->fWordY = y; + if (w == 0) { + pLine->m_LineInfo.fLineX = x; + } + if (w != m_pSection->m_WordArray.GetSize() - 1) { + pWord->fWordTail = + (fNodeWidth - (fWordWidth + fNextWidth) * PVT_HALF > 0 + ? fNodeWidth - (fWordWidth + fNextWidth) * PVT_HALF + : 0); + } else { + pWord->fWordTail = 0; + } + x += fWordWidth; + fLineAscent = std::max(fLineAscent, fWordAscent); + fLineDescent = std::min(fLineDescent, fWordDescent); + } + } + pLine->m_LineInfo.nBeginWordIndex = 0; + pLine->m_LineInfo.nEndWordIndex = m_pSection->m_WordArray.GetSize() - 1; + pLine->m_LineInfo.fLineY = y; + pLine->m_LineInfo.fLineWidth = x - pLine->m_LineInfo.fLineX; + pLine->m_LineInfo.fLineAscent = fLineAscent; + pLine->m_LineInfo.fLineDescent = fLineDescent; + y += (-fLineDescent); + } + return m_rcRet = CPVT_FloatRect(0, 0, x, y); +} +CPVT_Size CTypeset::GetEditSize(FX_FLOAT fFontSize) { + ASSERT(m_pSection); + ASSERT(m_pVT); + SplitLines(FALSE, fFontSize); + return CPVT_Size(m_rcRet.Width(), m_rcRet.Height()); +} +CPVT_FloatRect CTypeset::Typeset() { + ASSERT(m_pVT); + m_pSection->m_LineArray.Empty(); + SplitLines(TRUE, 0.0f); + m_pSection->m_LineArray.Clear(); + OutputLines(); + return m_rcRet; +} +static int special_chars[128] = { + 0x0000, 0x000C, 0x0008, 0x000C, 0x0008, 0x0000, 0x0020, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, + 0x0010, 0x0000, 0x0000, 0x0028, 0x000C, 0x0008, 0x0000, 0x0000, 0x0028, + 0x0028, 0x0028, 0x0028, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x000C, 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x000C, 0x0000, 0x0008, + 0x0000, 0x0000, +}; +static FX_BOOL IsLatin(FX_WORD word) { + if (word <= 0x007F) { + if (special_chars[word] & 0x0001) { + return TRUE; + } + } + if ((word >= 0x00C0 && word <= 0x00FF) || + (word >= 0x0100 && word <= 0x024F) || + (word >= 0x1E00 && word <= 0x1EFF) || + (word >= 0x2C60 && word <= 0x2C7F) || + (word >= 0xA720 && word <= 0xA7FF) || + (word >= 0xFF21 && word <= 0xFF3A) || + (word >= 0xFF41 && word <= 0xFF5A)) { + return TRUE; + } + return FALSE; +} +static FX_BOOL IsDigit(FX_DWORD word) { + return word >= 0x0030 && word <= 0x0039; +} +static FX_BOOL IsCJK(FX_DWORD word) { + if ((word >= 0x1100 && word <= 0x11FF) || + (word >= 0x2E80 && word <= 0x2FFF) || + (word >= 0x3040 && word <= 0x9FBF) || + (word >= 0xAC00 && word <= 0xD7AF) || + (word >= 0xF900 && word <= 0xFAFF) || + (word >= 0xFE30 && word <= 0xFE4F) || + (word >= 0x20000 && word <= 0x2A6DF) || + (word >= 0x2F800 && word <= 0x2FA1F)) { + return TRUE; + } + if (word >= 0x3000 && word <= 0x303F) { + if (word == 0x3005 || word == 0x3006 || word == 0x3021 || word == 0x3022 || + word == 0x3023 || word == 0x3024 || word == 0x3025 || word == 0x3026 || + word == 0x3027 || word == 0x3028 || word == 0x3029 || word == 0x3031 || + word == 0x3032 || word == 0x3033 || word == 0x3034 || word == 0x3035) { + return TRUE; + } + return FALSE; + } + if (word >= 0xFF66 && word <= 0xFF9D) { + return TRUE; + } + return FALSE; +} +static FX_BOOL IsPunctuation(FX_DWORD word) { + if (word <= 0x007F) { + if ((special_chars[word] >> 3) & 1) { + return TRUE; + } + } else if (word >= 0x0080 && word <= 0x00FF) { + if (word == 0x0082 || word == 0x0084 || word == 0x0085 || word == 0x0091 || + word == 0x0092 || word == 0x0093 || word <= 0x0094 || word == 0x0096 || + word == 0x00B4 || word == 0x00B8) { + return TRUE; + } + } else if (word >= 0x2000 && word <= 0x206F) { + if (word == 0x2010 || word == 0x2011 || word == 0x2012 || word == 0x2013 || + word == 0x2018 || word == 0x2019 || word == 0x201A || word == 0x201B || + word == 0x201C || word == 0x201D || word == 0x201E || word == 0x201F || + word == 0x2032 || word == 0x2033 || word == 0x2034 || word == 0x2035 || + word == 0x2036 || word == 0x2037 || word == 0x203C || word == 0x203D || + word == 0x203E || word == 0x2044) { + return TRUE; + } + } else if (word >= 0x3000 && word <= 0x303F) { + if (word == 0x3001 || word == 0x3002 || word == 0x3003 || word == 0x3005 || + word == 0x3009 || word == 0x300A || word == 0x300B || word == 0x300C || + word == 0x300D || word == 0x300F || word == 0x300E || word == 0x3010 || + word == 0x3011 || word == 0x3014 || word == 0x3015 || word == 0x3016 || + word == 0x3017 || word == 0x3018 || word == 0x3019 || word == 0x301A || + word == 0x301B || word == 0x301D || word == 0x301E || word == 0x301F) { + return TRUE; + } + } else if (word >= 0xFE50 && word <= 0xFE6F) { + if ((word >= 0xFE50 && word <= 0xFE5E) || word == 0xFE63) { + return TRUE; + } + } else if (word >= 0xFF00 && word <= 0xFFEF) { + if (word == 0xFF01 || word == 0xFF02 || word == 0xFF07 || word == 0xFF08 || + word == 0xFF09 || word == 0xFF0C || word == 0xFF0E || word == 0xFF0F || + word == 0xFF1A || word == 0xFF1B || word == 0xFF1F || word == 0xFF3B || + word == 0xFF3D || word == 0xFF40 || word == 0xFF5B || word == 0xFF5C || + word == 0xFF5D || word == 0xFF61 || word == 0xFF62 || word == 0xFF63 || + word == 0xFF64 || word == 0xFF65 || word == 0xFF9E || word == 0xFF9F) { + return TRUE; + } + } + return FALSE; +} +static FX_BOOL IsConnectiveSymbol(FX_DWORD word) { + if (word <= 0x007F) { + if ((special_chars[word] >> 5) & 1) { + return TRUE; + } + } + return FALSE; +} +static FX_BOOL IsOpenStylePunctuation(FX_DWORD word) { + if (word <= 0x007F) { + if ((special_chars[word] >> 2) & 1) { + return TRUE; + } + } else if (word == 0x300A || word == 0x300C || word == 0x300E || + word == 0x3010 || word == 0x3014 || word == 0x3016 || + word == 0x3018 || word == 0x301A || word == 0xFF08 || + word == 0xFF3B || word == 0xFF5B || word == 0xFF62) { + return TRUE; + } + return FALSE; +} +static FX_BOOL IsCurrencySymbol(FX_WORD word) { + if (word == 0x0024 || word == 0x0080 || word == 0x00A2 || word == 0x00A3 || + word == 0x00A4 || word == 0x00A5 || (word >= 0x20A0 && word <= 0x20CF) || + word == 0xFE69 || word == 0xFF04 || word == 0xFFE0 || word == 0xFFE1 || + word == 0xFFE5 || word == 0xFFE6) { + return TRUE; + } + return FALSE; +} +static FX_BOOL IsPrefixSymbol(FX_WORD word) { + if (IsCurrencySymbol(word)) { + return TRUE; + } + if (word == 0x2116) { + return TRUE; + } + return FALSE; +} +static FX_BOOL IsSpace(FX_WORD word) { + return word == 0x0020 || word == 0x3000; +} +static FX_BOOL NeedDivision(FX_WORD prevWord, FX_WORD curWord) { + if ((IsLatin(prevWord) || IsDigit(prevWord)) && + (IsLatin(curWord) || IsDigit(curWord))) { + return FALSE; + } + if (IsSpace(curWord) || IsPunctuation(curWord)) { + return FALSE; + } + if (IsConnectiveSymbol(prevWord) || IsConnectiveSymbol(curWord)) { + return FALSE; + } + if (IsSpace(prevWord) || IsPunctuation(prevWord)) { + return TRUE; + } + if (IsPrefixSymbol(prevWord)) { + return FALSE; + } + if (IsPrefixSymbol(curWord) || IsCJK(curWord)) { + return TRUE; + } + if (IsCJK(prevWord)) { + return TRUE; + } + return FALSE; +} +void CTypeset::SplitLines(FX_BOOL bTypeset, FX_FLOAT fFontSize) { + ASSERT(m_pVT); + ASSERT(m_pSection); + int32_t nLineHead = 0; + int32_t nLineTail = 0; + FX_FLOAT fMaxX = 0.0f, fMaxY = 0.0f; + FX_FLOAT fLineWidth = 0.0f, fBackupLineWidth = 0.0f; + FX_FLOAT fLineAscent = 0.0f, fBackupLineAscent = 0.0f; + FX_FLOAT fLineDescent = 0.0f, fBackupLineDescent = 0.0f; + int32_t nWordStartPos = 0; + FX_BOOL bFullWord = FALSE; + int32_t nLineFullWordIndex = 0; + int32_t nCharIndex = 0; + CPVT_LineInfo line; + FX_FLOAT fWordWidth = 0; + FX_FLOAT fTypesetWidth = std::max( + m_pVT->GetPlateWidth() - m_pVT->GetLineIndent(m_pSection->m_SecInfo), + 0.0f); + int32_t nTotalWords = m_pSection->m_WordArray.GetSize(); + FX_BOOL bOpened = FALSE; + if (nTotalWords > 0) { + int32_t i = 0; + while (i < nTotalWords) { + CPVT_WordInfo* pWord = m_pSection->m_WordArray.GetAt(i); + CPVT_WordInfo* pOldWord = pWord; + if (i > 0) { + pOldWord = m_pSection->m_WordArray.GetAt(i - 1); + } + if (pWord) { + if (bTypeset) { + fLineAscent = + std::max(fLineAscent, m_pVT->GetWordAscent(*pWord, TRUE)); + fLineDescent = + std::min(fLineDescent, m_pVT->GetWordDescent(*pWord, TRUE)); + fWordWidth = m_pVT->GetWordWidth(*pWord); + } else { + fLineAscent = + std::max(fLineAscent, m_pVT->GetWordAscent(*pWord, fFontSize)); + fLineDescent = + std::min(fLineDescent, m_pVT->GetWordDescent(*pWord, fFontSize)); + fWordWidth = m_pVT->GetWordWidth( + pWord->nFontIndex, pWord->Word, m_pVT->m_wSubWord, + m_pVT->m_fCharSpace, m_pVT->m_nHorzScale, fFontSize, + pWord->fWordTail, 0); + } + if (!bOpened) { + if (IsOpenStylePunctuation(pWord->Word)) { + bOpened = TRUE; + bFullWord = TRUE; + } else if (pOldWord) { + if (NeedDivision(pOldWord->Word, pWord->Word)) { + bFullWord = TRUE; + } + } + } else { + if (!IsSpace(pWord->Word) && !IsOpenStylePunctuation(pWord->Word)) { + bOpened = FALSE; + } + } + if (bFullWord) { + bFullWord = FALSE; + if (nCharIndex > 0) { + nLineFullWordIndex++; + } + nWordStartPos = i; + fBackupLineWidth = fLineWidth; + fBackupLineAscent = fLineAscent; + fBackupLineDescent = fLineDescent; + } + nCharIndex++; + } + if (m_pVT->m_bLimitWidth && fTypesetWidth > 0 && + fLineWidth + fWordWidth > fTypesetWidth) { + if (nLineFullWordIndex > 0) { + i = nWordStartPos; + fLineWidth = fBackupLineWidth; + fLineAscent = fBackupLineAscent; + fLineDescent = fBackupLineDescent; + } + if (nCharIndex == 1) { + fLineWidth = fWordWidth; + i++; + } + nLineTail = i - 1; + if (bTypeset) { + line.nBeginWordIndex = nLineHead; + line.nEndWordIndex = nLineTail; + line.nTotalWord = nLineTail - nLineHead + 1; + line.fLineWidth = fLineWidth; + line.fLineAscent = fLineAscent; + line.fLineDescent = fLineDescent; + m_pSection->AddLine(line); + } + fMaxY += (fLineAscent + m_pVT->GetLineLeading(m_pSection->m_SecInfo)); + fMaxY += (-fLineDescent); + fMaxX = std::max(fLineWidth, fMaxX); + nLineHead = i; + fLineWidth = 0.0f; + fLineAscent = 0.0f; + fLineDescent = 0.0f; + nCharIndex = 0; + nLineFullWordIndex = 0; + bFullWord = FALSE; + } else { + fLineWidth += fWordWidth; + i++; + } + } + if (nLineHead <= nTotalWords - 1) { + nLineTail = nTotalWords - 1; + if (bTypeset) { + line.nBeginWordIndex = nLineHead; + line.nEndWordIndex = nLineTail; + line.nTotalWord = nLineTail - nLineHead + 1; + line.fLineWidth = fLineWidth; + line.fLineAscent = fLineAscent; + line.fLineDescent = fLineDescent; + m_pSection->AddLine(line); + } + fMaxY += (fLineAscent + m_pVT->GetLineLeading(m_pSection->m_SecInfo)); + fMaxY += (-fLineDescent); + fMaxX = std::max(fLineWidth, fMaxX); + } + } else { + if (bTypeset) { + fLineAscent = m_pVT->GetLineAscent(m_pSection->m_SecInfo); + fLineDescent = m_pVT->GetLineDescent(m_pSection->m_SecInfo); + } else { + fLineAscent = + m_pVT->GetFontAscent(m_pVT->GetDefaultFontIndex(), fFontSize); + fLineDescent = + m_pVT->GetFontDescent(m_pVT->GetDefaultFontIndex(), fFontSize); + } + if (bTypeset) { + line.nBeginWordIndex = -1; + line.nEndWordIndex = -1; + line.nTotalWord = 0; + line.fLineWidth = 0; + line.fLineAscent = fLineAscent; + line.fLineDescent = fLineDescent; + m_pSection->AddLine(line); + } + fMaxY += (m_pVT->GetLineLeading(m_pSection->m_SecInfo) + fLineAscent + + (-fLineDescent)); + } + m_rcRet = CPVT_FloatRect(0, 0, fMaxX, fMaxY); +} +void CTypeset::OutputLines() { + ASSERT(m_pVT); + ASSERT(m_pSection); + FX_FLOAT fMinX = 0.0f, fMinY = 0.0f, fMaxX = 0.0f, fMaxY = 0.0f; + FX_FLOAT fPosX = 0.0f, fPosY = 0.0f; + FX_FLOAT fLineIndent = m_pVT->GetLineIndent(m_pSection->m_SecInfo); + FX_FLOAT fTypesetWidth = std::max(m_pVT->GetPlateWidth() - fLineIndent, 0.0f); + switch (m_pVT->GetAlignment(m_pSection->m_SecInfo)) { + default: + case 0: + fMinX = 0.0f; + break; + case 1: + fMinX = (fTypesetWidth - m_rcRet.Width()) * PVT_HALF; + break; + case 2: + fMinX = fTypesetWidth - m_rcRet.Width(); + break; + } + fMaxX = fMinX + m_rcRet.Width(); + fMinY = 0.0f; + fMaxY = m_rcRet.Height(); + int32_t nTotalLines = m_pSection->m_LineArray.GetSize(); + if (nTotalLines > 0) { + m_pSection->m_SecInfo.nTotalLine = nTotalLines; + for (int32_t l = 0; l < nTotalLines; l++) { + if (CLine* pLine = m_pSection->m_LineArray.GetAt(l)) { + switch (m_pVT->GetAlignment(m_pSection->m_SecInfo)) { + default: + case 0: + fPosX = 0; + break; + case 1: + fPosX = (fTypesetWidth - pLine->m_LineInfo.fLineWidth) * PVT_HALF; + break; + case 2: + fPosX = fTypesetWidth - pLine->m_LineInfo.fLineWidth; + break; + } + fPosX += fLineIndent; + fPosY += m_pVT->GetLineLeading(m_pSection->m_SecInfo); + fPosY += pLine->m_LineInfo.fLineAscent; + pLine->m_LineInfo.fLineX = fPosX - fMinX; + pLine->m_LineInfo.fLineY = fPosY - fMinY; + for (int32_t w = pLine->m_LineInfo.nBeginWordIndex; + w <= pLine->m_LineInfo.nEndWordIndex; w++) { + if (CPVT_WordInfo* pWord = m_pSection->m_WordArray.GetAt(w)) { + pWord->fWordX = fPosX - fMinX; + if (pWord->pWordProps) { + switch (pWord->pWordProps->nScriptType) { + default: + case PVTWORD_SCRIPT_NORMAL: + pWord->fWordY = fPosY - fMinY; + break; + case PVTWORD_SCRIPT_SUPER: + pWord->fWordY = fPosY - m_pVT->GetWordAscent(*pWord) - fMinY; + break; + case PVTWORD_SCRIPT_SUB: + pWord->fWordY = fPosY - m_pVT->GetWordDescent(*pWord) - fMinY; + break; + } + } else { + pWord->fWordY = fPosY - fMinY; + } + fPosX += m_pVT->GetWordWidth(*pWord); + } + } + fPosY += (-pLine->m_LineInfo.fLineDescent); + } + } + } + m_rcRet = CPVT_FloatRect(fMinX, fMinY, fMaxX, fMaxY); +} +CPDF_VariableText::CPDF_VariableText() + : m_nLimitChar(0), + m_nCharArray(0), + m_bMultiLine(FALSE), + m_bLimitWidth(FALSE), + m_bAutoFontSize(FALSE), + m_nAlignment(0), + m_fLineLeading(0.0f), + m_fCharSpace(0.0f), + m_nHorzScale(100), + m_wSubWord(0), + m_fFontSize(0.0f), + m_bInitial(FALSE), + m_bRichText(FALSE), + m_pVTProvider(NULL), + m_pVTIterator(NULL) {} +CPDF_VariableText::~CPDF_VariableText() { + delete m_pVTIterator; + m_pVTIterator = NULL; + ResetAll(); +} +void CPDF_VariableText::Initialize() { + if (!m_bInitial) { + CPVT_SectionInfo secinfo; + if (m_bRichText) { + secinfo.pSecProps = new CPVT_SecProps(0.0f, 0.0f, 0); + secinfo.pWordProps = new CPVT_WordProps(GetDefaultFontIndex(), + PVT_DEFAULT_FONTSIZE, 0, 0, 0); + } + CPVT_WordPlace place; + place.nSecIndex = 0; + AddSection(place, secinfo); + CPVT_LineInfo lineinfo; + lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize()); + lineinfo.fLineDescent = + GetFontDescent(GetDefaultFontIndex(), GetFontSize()); + AddLine(place, lineinfo); + if (CSection* pSection = m_SectionArray.GetAt(0)) { + pSection->ResetLinePlace(); + } + m_bInitial = TRUE; + } +} +void CPDF_VariableText::ResetAll() { + m_bInitial = FALSE; + ResetSectionArray(); +} +CPVT_WordPlace CPDF_VariableText::InsertWord(const CPVT_WordPlace& place, + FX_WORD word, + int32_t charset, + const CPVT_WordProps* pWordProps) { + int32_t nTotlaWords = GetTotalWords(); + if (m_nLimitChar > 0 && nTotlaWords >= m_nLimitChar) { + return place; + } + if (m_nCharArray > 0 && nTotlaWords >= m_nCharArray) { + return place; + } + CPVT_WordPlace newplace = place; + newplace.nWordIndex++; + if (m_bRichText) { + CPVT_WordProps* pNewProps = + pWordProps ? new CPVT_WordProps(*pWordProps) : new CPVT_WordProps(); + pNewProps->nFontIndex = + GetWordFontIndex(word, charset, pWordProps->nFontIndex); + return AddWord(newplace, CPVT_WordInfo(word, charset, -1, pNewProps)); + } + int32_t nFontIndex = + GetSubWord() > 0 ? GetDefaultFontIndex() + : GetWordFontIndex(word, charset, GetDefaultFontIndex()); + return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex, NULL)); +} +CPVT_WordPlace CPDF_VariableText::InsertSection( + const CPVT_WordPlace& place, + const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pWordProps) { + int32_t nTotlaWords = GetTotalWords(); + if (m_nLimitChar > 0 && nTotlaWords >= m_nLimitChar) { + return place; + } + if (m_nCharArray > 0 && nTotlaWords >= m_nCharArray) { + return place; + } + if (!m_bMultiLine) { + return place; + } + CPVT_WordPlace wordplace = place; + UpdateWordPlace(wordplace); + CPVT_WordPlace newplace = place; + if (CSection* pSection = m_SectionArray.GetAt(wordplace.nSecIndex)) { + CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1); + CPVT_SectionInfo secinfo; + if (m_bRichText) { + if (pSecProps) { + secinfo.pSecProps = new CPVT_SecProps(*pSecProps); + } + if (pWordProps) { + secinfo.pWordProps = new CPVT_WordProps(*pWordProps); + } + } + AddSection(NewPlace, secinfo); + newplace = NewPlace; + if (CSection* pNewSection = m_SectionArray.GetAt(NewPlace.nSecIndex)) { + for (int32_t w = wordplace.nWordIndex + 1, + sz = pSection->m_WordArray.GetSize(); + w < sz; w++) { + if (CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(w)) { + NewPlace.nWordIndex++; + pNewSection->AddWord(NewPlace, *pWord); + } + } + } + ClearSectionRightWords(wordplace); + } + return newplace; +} +CPVT_WordPlace CPDF_VariableText::InsertText(const CPVT_WordPlace& place, + const FX_WCHAR* text, + int32_t charset, + const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pProps) { + CFX_WideString swText = text; + CPVT_WordPlace wp = place; + for (int32_t i = 0, sz = swText.GetLength(); i < sz; i++) { + CPVT_WordPlace oldwp = wp; + FX_WORD word = swText.GetAt(i); + switch (word) { + case 0x0D: + if (m_bMultiLine) { + if (swText.GetAt(i + 1) == 0x0A) { + i += 1; + } + wp = InsertSection(wp, pSecProps, pProps); + } + break; + case 0x0A: + if (m_bMultiLine) { + if (swText.GetAt(i + 1) == 0x0D) { + i += 1; + } + wp = InsertSection(wp, pSecProps, pProps); + } + break; + case 0x09: + word = 0x20; + default: + wp = InsertWord(wp, word, charset, pProps); + break; + } + if (wp == oldwp) { + break; + } + } + return wp; +} +CPVT_WordPlace CPDF_VariableText::DeleteWords( + const CPVT_WordRange& PlaceRange) { + FX_BOOL bLastSecPos = FALSE; + if (CSection* pSection = m_SectionArray.GetAt(PlaceRange.EndPos.nSecIndex)) { + bLastSecPos = (PlaceRange.EndPos == pSection->GetEndWordPlace()); + } + ClearWords(PlaceRange); + if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) { + ClearEmptySections(PlaceRange); + if (!bLastSecPos) { + LinkLatterSection(PlaceRange.BeginPos); + } + } + return PlaceRange.BeginPos; +} +CPVT_WordPlace CPDF_VariableText::DeleteWord(const CPVT_WordPlace& place) { + return ClearRightWord(AdjustLineHeader(place, TRUE)); +} +CPVT_WordPlace CPDF_VariableText::BackSpaceWord(const CPVT_WordPlace& place) { + return ClearLeftWord(AdjustLineHeader(place, TRUE)); +} +void CPDF_VariableText::SetText(const FX_WCHAR* text, + int32_t charset, + const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pWordProps) { + DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); + CFX_WideString swText = text; + CPVT_WordPlace wp(0, 0, -1); + CPVT_SectionInfo secinfo; + if (m_bRichText) { + if (pSecProps) { + secinfo.pSecProps = new CPVT_SecProps(*pSecProps); + } + if (pWordProps) { + secinfo.pWordProps = new CPVT_WordProps(*pWordProps); + } + } + if (CSection* pSection = m_SectionArray.GetAt(0)) { + pSection->m_SecInfo = secinfo; + } + int32_t nCharCount = 0; + for (int32_t i = 0, sz = swText.GetLength(); i < sz; i++) { + if (m_nLimitChar > 0 && nCharCount >= m_nLimitChar) { + break; + } + if (m_nCharArray > 0 && nCharCount >= m_nCharArray) { + break; + } + FX_WORD word = swText.GetAt(i); + switch (word) { + case 0x0D: + if (m_bMultiLine) { + if (swText.GetAt(i + 1) == 0x0A) { + i += 1; + } + wp.nSecIndex++; + wp.nLineIndex = 0; + wp.nWordIndex = -1; + AddSection(wp, secinfo); + } + break; + case 0x0A: + if (m_bMultiLine) { + if (swText.GetAt(i + 1) == 0x0D) { + i += 1; + } + wp.nSecIndex++; + wp.nLineIndex = 0; + wp.nWordIndex = -1; + AddSection(wp, secinfo); + } + break; + case 0x09: + word = 0x20; + default: + wp = InsertWord(wp, word, charset, pWordProps); + break; + } + nCharCount++; + } +} +void CPDF_VariableText::UpdateWordPlace(CPVT_WordPlace& place) const { + if (place.nSecIndex < 0) { + place = GetBeginWordPlace(); + } + if (place.nSecIndex >= m_SectionArray.GetSize()) { + place = GetEndWordPlace(); + } + place = AdjustLineHeader(place, TRUE); + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + pSection->UpdateWordPlace(place); + } +} +int32_t CPDF_VariableText::WordPlaceToWordIndex( + const CPVT_WordPlace& place) const { + CPVT_WordPlace newplace = place; + UpdateWordPlace(newplace); + int32_t nIndex = 0; + int32_t i = 0; + int32_t sz = 0; + for (i = 0, sz = m_SectionArray.GetSize(); i < sz && i < newplace.nSecIndex; + i++) { + if (CSection* pSection = m_SectionArray.GetAt(i)) { + nIndex += pSection->m_WordArray.GetSize(); + if (i != m_SectionArray.GetSize() - 1) { + nIndex += PVT_RETURN_LENGTH; + } + } + } + if (i >= 0 && i < m_SectionArray.GetSize()) { + nIndex += newplace.nWordIndex + PVT_RETURN_LENGTH; + } + return nIndex; +} +CPVT_WordPlace CPDF_VariableText::WordIndexToWordPlace(int32_t index) const { + CPVT_WordPlace place = GetBeginWordPlace(); + int32_t nOldIndex = 0, nIndex = 0; + FX_BOOL bFind = FALSE; + for (int32_t i = 0, sz = m_SectionArray.GetSize(); i < sz; i++) { + if (CSection* pSection = m_SectionArray.GetAt(i)) { + nIndex += pSection->m_WordArray.GetSize(); + if (nIndex == index) { + place = pSection->GetEndWordPlace(); + bFind = TRUE; + break; + } else if (nIndex > index) { + place.nSecIndex = i; + place.nWordIndex = index - nOldIndex - 1; + pSection->UpdateWordPlace(place); + bFind = TRUE; + break; + } + if (i != m_SectionArray.GetSize() - 1) { + nIndex += PVT_RETURN_LENGTH; + } + nOldIndex = nIndex; + } + } + if (!bFind) { + place = GetEndWordPlace(); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::GetBeginWordPlace() const { + return m_bInitial ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace(); +} +CPVT_WordPlace CPDF_VariableText::GetEndWordPlace() const { + if (CSection* pSection = m_SectionArray.GetAt(m_SectionArray.GetSize() - 1)) { + return pSection->GetEndWordPlace(); + } + return CPVT_WordPlace(); +} +CPVT_WordPlace CPDF_VariableText::GetPrevWordPlace( + const CPVT_WordPlace& place) const { + if (place.nSecIndex < 0) { + return GetBeginWordPlace(); + } + if (place.nSecIndex >= m_SectionArray.GetSize()) { + return GetEndWordPlace(); + } + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (place.WordCmp(pSection->GetBeginWordPlace()) <= 0) { + if (CSection* pPrevSection = m_SectionArray.GetAt(place.nSecIndex - 1)) { + return pPrevSection->GetEndWordPlace(); + } + return GetBeginWordPlace(); + } + return pSection->GetPrevWordPlace(place); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::GetNextWordPlace( + const CPVT_WordPlace& place) const { + if (place.nSecIndex < 0) { + return GetBeginWordPlace(); + } + if (place.nSecIndex >= m_SectionArray.GetSize()) { + return GetEndWordPlace(); + } + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (place.WordCmp(pSection->GetEndWordPlace()) >= 0) { + if (CSection* pNextSection = m_SectionArray.GetAt(place.nSecIndex + 1)) { + return pNextSection->GetBeginWordPlace(); + } + return GetEndWordPlace(); + } + return pSection->GetNextWordPlace(place); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::SearchWordPlace( + const CFX_FloatPoint& point) const { + CFX_FloatPoint pt = OutToIn(point); + CPVT_WordPlace place = GetBeginWordPlace(); + int32_t nLeft = 0; + int32_t nRight = m_SectionArray.GetSize() - 1; + int32_t nMid = m_SectionArray.GetSize() / 2; + FX_BOOL bUp = TRUE; + FX_BOOL bDown = TRUE; + while (nLeft <= nRight) { + if (CSection* pSection = m_SectionArray.GetAt(nMid)) { + if (IsFloatBigger(pt.y, pSection->m_SecInfo.rcSection.top)) { + bUp = FALSE; + } + if (IsFloatBigger(pSection->m_SecInfo.rcSection.bottom, pt.y)) { + bDown = FALSE; + } + if (IsFloatSmaller(pt.y, pSection->m_SecInfo.rcSection.top)) { + nRight = nMid - 1; + nMid = (nLeft + nRight) / 2; + continue; + } else if (IsFloatBigger(pt.y, pSection->m_SecInfo.rcSection.bottom)) { + nLeft = nMid + 1; + nMid = (nLeft + nRight) / 2; + continue; + } else { + place = pSection->SearchWordPlace( + CFX_FloatPoint(pt.x - pSection->m_SecInfo.rcSection.left, + pt.y - pSection->m_SecInfo.rcSection.top)); + place.nSecIndex = nMid; + return place; + } + } else { + break; + } + } + if (bUp) { + place = GetBeginWordPlace(); + } + if (bDown) { + place = GetEndWordPlace(); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::GetUpWordPlace( + const CPVT_WordPlace& place, + const CFX_FloatPoint& point) const { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + CPVT_WordPlace temp = place; + CFX_FloatPoint pt = OutToIn(point); + if (temp.nLineIndex-- > 0) { + return pSection->SearchWordPlace( + pt.x - pSection->m_SecInfo.rcSection.left, temp); + } + if (temp.nSecIndex-- > 0) { + if (CSection* pLastSection = m_SectionArray.GetAt(temp.nSecIndex)) { + temp.nLineIndex = pLastSection->m_LineArray.GetSize() - 1; + return pLastSection->SearchWordPlace( + pt.x - pLastSection->m_SecInfo.rcSection.left, temp); + } + } + } + return place; +} +CPVT_WordPlace CPDF_VariableText::GetDownWordPlace( + const CPVT_WordPlace& place, + const CFX_FloatPoint& point) const { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + CPVT_WordPlace temp = place; + CFX_FloatPoint pt = OutToIn(point); + if (temp.nLineIndex++ < pSection->m_LineArray.GetSize() - 1) { + return pSection->SearchWordPlace( + pt.x - pSection->m_SecInfo.rcSection.left, temp); + } + if (temp.nSecIndex++ < m_SectionArray.GetSize() - 1) { + if (CSection* pNextSection = m_SectionArray.GetAt(temp.nSecIndex)) { + temp.nLineIndex = 0; + return pNextSection->SearchWordPlace( + pt.x - pSection->m_SecInfo.rcSection.left, temp); + } + } + } + return place; +} +CPVT_WordPlace CPDF_VariableText::GetLineBeginPlace( + const CPVT_WordPlace& place) const { + return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1); +} +CPVT_WordPlace CPDF_VariableText::GetLineEndPlace( + const CPVT_WordPlace& place) const { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (CLine* pLine = pSection->m_LineArray.GetAt(place.nLineIndex)) + return pLine->GetEndWordPlace(); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::GetSectionBeginPlace( + const CPVT_WordPlace& place) const { + return CPVT_WordPlace(place.nSecIndex, 0, -1); +} +CPVT_WordPlace CPDF_VariableText::GetSectionEndPlace( + const CPVT_WordPlace& place) const { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + return pSection->GetEndWordPlace(); + } + return place; +} +int32_t CPDF_VariableText::GetTotalWords() const { + int32_t nTotal = 0; + for (int32_t i = 0, sz = m_SectionArray.GetSize(); i < sz; i++) + if (CSection* pSection = m_SectionArray.GetAt(i)) { + nTotal += (pSection->m_WordArray.GetSize() + PVT_RETURN_LENGTH); + } + return nTotal - PVT_RETURN_LENGTH; +} +void CPDF_VariableText::ResetSectionArray() { + for (int32_t s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) { + delete m_SectionArray.GetAt(s); + } + m_SectionArray.RemoveAll(); +} +CPVT_WordPlace CPDF_VariableText::AddSection(const CPVT_WordPlace& place, + const CPVT_SectionInfo& secinfo) { + if (IsValid() && !m_bMultiLine) { + return place; + } + int32_t nSecIndex = + std::max(std::min(place.nSecIndex, m_SectionArray.GetSize()), 0); + CSection* pSection = new CSection(this); + pSection->m_SecInfo = secinfo; + pSection->SecPlace.nSecIndex = nSecIndex; + if (nSecIndex == m_SectionArray.GetSize()) { + m_SectionArray.Add(pSection); + } else { + m_SectionArray.InsertAt(nSecIndex, pSection); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::AddLine(const CPVT_WordPlace& place, + const CPVT_LineInfo& lineinfo) { + if (m_SectionArray.IsEmpty()) { + return place; + } + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + return pSection->AddLine(lineinfo); + } + return place; +} +CPVT_WordPlace CPDF_VariableText::AddWord(const CPVT_WordPlace& place, + const CPVT_WordInfo& wordinfo) { + if (m_SectionArray.GetSize() <= 0) { + return place; + } + CPVT_WordPlace newplace = place; + newplace.nSecIndex = + std::max(std::min(newplace.nSecIndex, m_SectionArray.GetSize() - 1), 0); + if (CSection* pSection = m_SectionArray.GetAt(newplace.nSecIndex)) { + return pSection->AddWord(newplace, wordinfo); + } + return place; +} +FX_BOOL CPDF_VariableText::GetWordInfo(const CPVT_WordPlace& place, + CPVT_WordInfo& wordinfo) { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(place.nWordIndex)) { + wordinfo = *pWord; + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText::SetWordInfo(const CPVT_WordPlace& place, + const CPVT_WordInfo& wordinfo) { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(place.nWordIndex)) { + *pWord = wordinfo; + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText::GetLineInfo(const CPVT_WordPlace& place, + CPVT_LineInfo& lineinfo) { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (CLine* pLine = pSection->m_LineArray.GetAt(place.nLineIndex)) { + lineinfo = pLine->m_LineInfo; + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText::GetSectionInfo(const CPVT_WordPlace& place, + CPVT_SectionInfo& secinfo) { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + secinfo = pSection->m_SecInfo; + return TRUE; + } + return FALSE; +} +CFX_FloatRect CPDF_VariableText::GetContentRect() const { + return InToOut(CPVT_FloatRect(CPDF_EditContainer::GetContentRect())); +} +FX_FLOAT CPDF_VariableText::GetWordFontSize(const CPVT_WordInfo& WordInfo, + FX_BOOL bFactFontSize) { + return m_bRichText && WordInfo.pWordProps + ? (WordInfo.pWordProps->nScriptType == PVTWORD_SCRIPT_NORMAL || + bFactFontSize + ? WordInfo.pWordProps->fFontSize + : WordInfo.pWordProps->fFontSize * PVT_HALF) + : GetFontSize(); +} +int32_t CPDF_VariableText::GetWordFontIndex(const CPVT_WordInfo& WordInfo) { + return m_bRichText && WordInfo.pWordProps ? WordInfo.pWordProps->nFontIndex + : WordInfo.nFontIndex; +} +FX_FLOAT CPDF_VariableText::GetWordWidth(int32_t nFontIndex, + FX_WORD Word, + FX_WORD SubWord, + FX_FLOAT fCharSpace, + int32_t nHorzScale, + FX_FLOAT fFontSize, + FX_FLOAT fWordTail, + int32_t nWordStyle) { + return (GetCharWidth(nFontIndex, Word, SubWord, nWordStyle) * fFontSize * + PVT_FONTSCALE + + fCharSpace) * + nHorzScale * PVT_PERCENT + + fWordTail; +} +FX_FLOAT CPDF_VariableText::GetWordWidth(const CPVT_WordInfo& WordInfo) { + return GetWordWidth( + GetWordFontIndex(WordInfo), WordInfo.Word, GetSubWord(), + GetCharSpace(WordInfo), GetHorzScale(WordInfo), GetWordFontSize(WordInfo), + WordInfo.fWordTail, + WordInfo.pWordProps ? WordInfo.pWordProps->nWordStyle : 0); +} +FX_FLOAT CPDF_VariableText::GetLineAscent(const CPVT_SectionInfo& SecInfo) { + return m_bRichText && SecInfo.pWordProps + ? GetFontAscent(SecInfo.pWordProps->nFontIndex, + SecInfo.pWordProps->fFontSize) + : GetFontAscent(GetDefaultFontIndex(), GetFontSize()); +} +FX_FLOAT CPDF_VariableText::GetLineDescent(const CPVT_SectionInfo& SecInfo) { + return m_bRichText && SecInfo.pWordProps + ? GetFontDescent(SecInfo.pWordProps->nFontIndex, + SecInfo.pWordProps->fFontSize) + : GetFontDescent(GetDefaultFontIndex(), GetFontSize()); +} +FX_FLOAT CPDF_VariableText::GetFontAscent(int32_t nFontIndex, + FX_FLOAT fFontSize) { + return (FX_FLOAT)GetTypeAscent(nFontIndex) * fFontSize * PVT_FONTSCALE; +} +FX_FLOAT CPDF_VariableText::GetFontDescent(int32_t nFontIndex, + FX_FLOAT fFontSize) { + return (FX_FLOAT)GetTypeDescent(nFontIndex) * fFontSize * PVT_FONTSCALE; +} +FX_FLOAT CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo, + FX_FLOAT fFontSize) { + return GetFontAscent(GetWordFontIndex(WordInfo), fFontSize); +} +FX_FLOAT CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo, + FX_FLOAT fFontSize) { + return GetFontDescent(GetWordFontIndex(WordInfo), fFontSize); +} +FX_FLOAT CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo, + FX_BOOL bFactFontSize) { + return GetFontAscent(GetWordFontIndex(WordInfo), + GetWordFontSize(WordInfo, bFactFontSize)); +} +FX_FLOAT CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo, + FX_BOOL bFactFontSize) { + return GetFontDescent(GetWordFontIndex(WordInfo), + GetWordFontSize(WordInfo, bFactFontSize)); +} +FX_FLOAT CPDF_VariableText::GetLineLeading(const CPVT_SectionInfo& SecInfo) { + return m_bRichText && SecInfo.pSecProps ? SecInfo.pSecProps->fLineLeading + : m_fLineLeading; +} +FX_FLOAT CPDF_VariableText::GetLineIndent(const CPVT_SectionInfo& SecInfo) { + return m_bRichText && SecInfo.pSecProps ? SecInfo.pSecProps->fLineIndent + : 0.0f; +} +int32_t CPDF_VariableText::GetAlignment(const CPVT_SectionInfo& SecInfo) { + return m_bRichText && SecInfo.pSecProps ? SecInfo.pSecProps->nAlignment + : m_nAlignment; +} +FX_FLOAT CPDF_VariableText::GetCharSpace(const CPVT_WordInfo& WordInfo) { + return m_bRichText && WordInfo.pWordProps ? WordInfo.pWordProps->fCharSpace + : m_fCharSpace; +} +int32_t CPDF_VariableText::GetHorzScale(const CPVT_WordInfo& WordInfo) { + return m_bRichText && WordInfo.pWordProps ? WordInfo.pWordProps->nHorzScale + : m_nHorzScale; +} +void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) { + CPVT_WordPlace wordplace = AdjustLineHeader(place, TRUE); + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + for (int32_t w = pSection->m_WordArray.GetSize() - 1; + w > wordplace.nWordIndex; w--) { + delete pSection->m_WordArray.GetAt(w); + pSection->m_WordArray.RemoveAt(w); + } + } +} +CPVT_WordPlace CPDF_VariableText::AdjustLineHeader(const CPVT_WordPlace& place, + FX_BOOL bPrevOrNext) const { + if (place.nWordIndex < 0 && place.nLineIndex > 0) { + return bPrevOrNext ? GetPrevWordPlace(place) : GetNextWordPlace(place); + } + return place; +} +FX_BOOL CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace& place) { + if (place.nSecIndex == 0 && m_SectionArray.GetSize() == 1) { + return FALSE; + } + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + if (pSection->m_WordArray.GetSize() == 0) { + delete pSection; + m_SectionArray.RemoveAt(place.nSecIndex); + return TRUE; + } + } + return FALSE; +} +void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) { + CPVT_WordPlace wordplace; + for (int32_t s = PlaceRange.EndPos.nSecIndex; + s > PlaceRange.BeginPos.nSecIndex; s--) { + wordplace.nSecIndex = s; + ClearEmptySection(wordplace); + } +} +void CPDF_VariableText::LinkLatterSection(const CPVT_WordPlace& place) { + CPVT_WordPlace oldplace = AdjustLineHeader(place, TRUE); + if (CSection* pNextSection = m_SectionArray.GetAt(place.nSecIndex + 1)) { + if (CSection* pSection = m_SectionArray.GetAt(oldplace.nSecIndex)) { + for (int32_t w = 0, sz = pNextSection->m_WordArray.GetSize(); w < sz; + w++) { + if (CPVT_WordInfo* pWord = pNextSection->m_WordArray.GetAt(w)) { + oldplace.nWordIndex++; + pSection->AddWord(oldplace, *pWord); + } + } + } + delete pNextSection; + m_SectionArray.RemoveAt(place.nSecIndex + 1); + } +} +void CPDF_VariableText::ClearWords(const CPVT_WordRange& PlaceRange) { + CPVT_WordRange NewRange; + NewRange.BeginPos = AdjustLineHeader(PlaceRange.BeginPos, TRUE); + NewRange.EndPos = AdjustLineHeader(PlaceRange.EndPos, TRUE); + for (int32_t s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex; + s--) { + if (CSection* pSection = m_SectionArray.GetAt(s)) { + pSection->ClearWords(NewRange); + } + } +} +CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace& place) { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + CPVT_WordPlace leftplace = GetPrevWordPlace(place); + if (leftplace != place) { + if (leftplace.nSecIndex != place.nSecIndex) { + if (pSection->m_WordArray.GetSize() == 0) { + ClearEmptySection(place); + } else { + LinkLatterSection(leftplace); + } + } else { + pSection->ClearWord(place); + } + } + return leftplace; + } + return place; +} +CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace& place) { + if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) { + CPVT_WordPlace rightplace = + AdjustLineHeader(GetNextWordPlace(place), FALSE); + if (rightplace != place) { + if (rightplace.nSecIndex != place.nSecIndex) { + LinkLatterSection(place); + } else { + pSection->ClearWord(rightplace); + } + } + } + return place; +} +void CPDF_VariableText::RearrangeAll() { + Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); +} +void CPDF_VariableText::RearrangePart(const CPVT_WordRange& PlaceRange) { + Rearrange(PlaceRange); +} +CPVT_FloatRect CPDF_VariableText::Rearrange(const CPVT_WordRange& PlaceRange) { + CPVT_FloatRect rcRet; + if (IsValid()) { + if (m_bAutoFontSize) { + SetFontSize(GetAutoFontSize()); + rcRet = RearrangeSections( + CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); + } else { + rcRet = RearrangeSections(PlaceRange); + } + } + SetContentRect(rcRet); + return rcRet; +} +FX_FLOAT CPDF_VariableText::GetAutoFontSize() { + int32_t nTotal = sizeof(gFontSizeSteps) / sizeof(uint8_t); + if (IsMultiLine()) { + nTotal /= 4; + } + if (nTotal <= 0) { + return 0; + } + if (GetPlateWidth() <= 0) { + return 0; + } + int32_t nLeft = 0; + int32_t nRight = nTotal - 1; + int32_t nMid = nTotal / 2; + while (nLeft <= nRight) { + if (IsBigger(gFontSizeSteps[nMid])) { + nRight = nMid - 1; + nMid = (nLeft + nRight) / 2; + continue; + } else { + nLeft = nMid + 1; + nMid = (nLeft + nRight) / 2; + continue; + } + } + return (FX_FLOAT)gFontSizeSteps[nMid]; +} +FX_BOOL CPDF_VariableText::IsBigger(FX_FLOAT fFontSize) { + FX_BOOL bBigger = FALSE; + CPVT_Size szTotal; + for (int32_t s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) { + if (CSection* pSection = m_SectionArray.GetAt(s)) { + CPVT_Size size = pSection->GetSectionSize(fFontSize); + szTotal.x = std::max(size.x, szTotal.x); + szTotal.y += size.y; + if (IsFloatBigger(szTotal.x, GetPlateWidth()) || + IsFloatBigger(szTotal.y, GetPlateHeight())) { + bBigger = TRUE; + break; + } + } + } + return bBigger; +} +CPVT_FloatRect CPDF_VariableText::RearrangeSections( + const CPVT_WordRange& PlaceRange) { + CPVT_WordPlace place; + FX_FLOAT fPosY = 0; + FX_FLOAT fOldHeight; + int32_t nSSecIndex = PlaceRange.BeginPos.nSecIndex; + int32_t nESecIndex = PlaceRange.EndPos.nSecIndex; + CPVT_FloatRect rcRet; + for (int32_t s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) { + place.nSecIndex = s; + if (CSection* pSection = m_SectionArray.GetAt(s)) { + pSection->SecPlace = place; + CPVT_FloatRect rcSec = pSection->m_SecInfo.rcSection; + if (s >= nSSecIndex) { + if (s <= nESecIndex) { + rcSec = pSection->Rearrange(); + rcSec.top += fPosY; + rcSec.bottom += fPosY; + } else { + fOldHeight = pSection->m_SecInfo.rcSection.bottom - + pSection->m_SecInfo.rcSection.top; + rcSec.top = fPosY; + rcSec.bottom = fPosY + fOldHeight; + } + pSection->m_SecInfo.rcSection = rcSec; + pSection->ResetLinePlace(); + } + if (s == 0) { + rcRet = rcSec; + } else { + rcRet.left = std::min(rcSec.left, rcRet.left); + rcRet.top = std::min(rcSec.top, rcRet.top); + rcRet.right = std::max(rcSec.right, rcRet.right); + rcRet.bottom = std::max(rcSec.bottom, rcRet.bottom); + } + fPosY += rcSec.Height(); + } + } + return rcRet; +} +int32_t CPDF_VariableText::GetCharWidth(int32_t nFontIndex, + FX_WORD Word, + FX_WORD SubWord, + int32_t nWordStyle) { + if (!m_pVTProvider) { + return 0; + } + if (SubWord > 0) { + return m_pVTProvider->GetCharWidth(nFontIndex, SubWord, nWordStyle); + } + return m_pVTProvider->GetCharWidth(nFontIndex, Word, nWordStyle); +} +int32_t CPDF_VariableText::GetTypeAscent(int32_t nFontIndex) { + return m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0; +} +int32_t CPDF_VariableText::GetTypeDescent(int32_t nFontIndex) { + return m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0; +} +int32_t CPDF_VariableText::GetWordFontIndex(FX_WORD word, + int32_t charset, + int32_t nFontIndex) { + return m_pVTProvider + ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex) + : -1; +} +int32_t CPDF_VariableText::GetDefaultFontIndex() { + return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1; +} +FX_BOOL CPDF_VariableText::IsLatinWord(FX_WORD word) { + return m_pVTProvider ? m_pVTProvider->IsLatinWord(word) : FALSE; +} +IPDF_VariableText_Iterator* CPDF_VariableText::GetIterator() { + if (!m_pVTIterator) { + m_pVTIterator = new CPDF_VariableText_Iterator(this); + } + return m_pVTIterator; +} +IPDF_VariableText_Provider* CPDF_VariableText::SetProvider( + IPDF_VariableText_Provider* pProvider) { + IPDF_VariableText_Provider* pOld = m_pVTProvider; + m_pVTProvider = pProvider; + return pOld; +} +CPDF_VariableText_Iterator::CPDF_VariableText_Iterator(CPDF_VariableText* pVT) + : m_CurPos(-1, -1, -1), m_pVT(pVT) {} +CPDF_VariableText_Iterator::~CPDF_VariableText_Iterator() {} +void CPDF_VariableText_Iterator::SetAt(int32_t nWordIndex) { + m_CurPos = m_pVT->WordIndexToWordPlace(nWordIndex); +} +void CPDF_VariableText_Iterator::SetAt(const CPVT_WordPlace& place) { + ASSERT(m_pVT); + m_CurPos = place; +} +FX_BOOL CPDF_VariableText_Iterator::NextWord() { + if (m_CurPos == m_pVT->GetEndWordPlace()) { + return FALSE; + } + m_CurPos = m_pVT->GetNextWordPlace(m_CurPos); + return TRUE; +} +FX_BOOL CPDF_VariableText_Iterator::PrevWord() { + if (m_CurPos == m_pVT->GetBeginWordPlace()) { + return FALSE; + } + m_CurPos = m_pVT->GetPrevWordPlace(m_CurPos); + return TRUE; +} +FX_BOOL CPDF_VariableText_Iterator::NextLine() { + if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + if (m_CurPos.nLineIndex < pSection->m_LineArray.GetSize() - 1) { + m_CurPos = + CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex + 1, -1); + return TRUE; + } + if (m_CurPos.nSecIndex < m_pVT->m_SectionArray.GetSize() - 1) { + m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1); + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::PrevLine() { + if (m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + if (m_CurPos.nLineIndex > 0) { + m_CurPos = + CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex - 1, -1); + return TRUE; + } + if (m_CurPos.nSecIndex > 0) { + if (CSection* pLastSection = + m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex - 1)) { + m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex - 1, + pLastSection->m_LineArray.GetSize() - 1, -1); + return TRUE; + } + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::NextSection() { + if (m_CurPos.nSecIndex < m_pVT->m_SectionArray.GetSize() - 1) { + m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1); + return TRUE; + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::PrevSection() { + ASSERT(m_pVT); + if (m_CurPos.nSecIndex > 0) { + m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex - 1, 0, -1); + return TRUE; + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::GetWord(CPVT_Word& word) const { + word.WordPlace = m_CurPos; + if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + if (pSection->m_LineArray.GetAt(m_CurPos.nLineIndex)) { + if (CPVT_WordInfo* pWord = + pSection->m_WordArray.GetAt(m_CurPos.nWordIndex)) { + word.Word = pWord->Word; + word.nCharset = pWord->nCharset; + word.fWidth = m_pVT->GetWordWidth(*pWord); + word.ptWord = m_pVT->InToOut( + CFX_FloatPoint(pWord->fWordX + pSection->m_SecInfo.rcSection.left, + pWord->fWordY + pSection->m_SecInfo.rcSection.top)); + word.fAscent = m_pVT->GetWordAscent(*pWord); + word.fDescent = m_pVT->GetWordDescent(*pWord); + if (pWord->pWordProps) { + word.WordProps = *pWord->pWordProps; + } + word.nFontIndex = m_pVT->GetWordFontIndex(*pWord); + word.fFontSize = m_pVT->GetWordFontSize(*pWord); + return TRUE; + } + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::SetWord(const CPVT_Word& word) { + if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + if (CPVT_WordInfo* pWord = + pSection->m_WordArray.GetAt(m_CurPos.nWordIndex)) { + if (pWord->pWordProps) { + *pWord->pWordProps = word.WordProps; + } + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::GetLine(CPVT_Line& line) const { + ASSERT(m_pVT); + line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1); + if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + if (CLine* pLine = pSection->m_LineArray.GetAt(m_CurPos.nLineIndex)) { + line.ptLine = m_pVT->InToOut(CFX_FloatPoint( + pLine->m_LineInfo.fLineX + pSection->m_SecInfo.rcSection.left, + pLine->m_LineInfo.fLineY + pSection->m_SecInfo.rcSection.top)); + line.fLineWidth = pLine->m_LineInfo.fLineWidth; + line.fLineAscent = pLine->m_LineInfo.fLineAscent; + line.fLineDescent = pLine->m_LineInfo.fLineDescent; + line.lineEnd = pLine->GetEndWordPlace(); + return TRUE; + } + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::GetSection(CPVT_Section& section) const { + section.secplace = CPVT_WordPlace(m_CurPos.nSecIndex, 0, -1); + if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + section.rcSection = m_pVT->InToOut(pSection->m_SecInfo.rcSection); + if (pSection->m_SecInfo.pSecProps) { + section.SecProps = *pSection->m_SecInfo.pSecProps; + } + if (pSection->m_SecInfo.pWordProps) { + section.WordProps = *pSection->m_SecInfo.pWordProps; + } + return TRUE; + } + return FALSE; +} +FX_BOOL CPDF_VariableText_Iterator::SetSection(const CPVT_Section& section) { + if (CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) { + if (pSection->m_SecInfo.pSecProps) { + *pSection->m_SecInfo.pSecProps = section.SecProps; + } + if (pSection->m_SecInfo.pWordProps) { + *pSection->m_SecInfo.pWordProps = section.WordProps; + } + return TRUE; + } + return FALSE; +} diff --git a/core/fpdfdoc/doc_vtmodule.cpp b/core/fpdfdoc/doc_vtmodule.cpp new file mode 100644 index 0000000000..85e19ffd08 --- /dev/null +++ b/core/fpdfdoc/doc_vtmodule.cpp @@ -0,0 +1,16 @@ +// 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/fpdfdoc/pdf_vt.h" +#include "core/include/fpdfdoc/fpdf_doc.h" +#include "core/include/fpdfdoc/fpdf_vt.h" + +IPDF_VariableText* IPDF_VariableText::NewVariableText() { + return new CPDF_VariableText(); +} +void IPDF_VariableText::DelVariableText(IPDF_VariableText* pVT) { + delete (CPDF_VariableText*)pVT; +} diff --git a/core/fpdfdoc/pdf_vt.h b/core/fpdfdoc/pdf_vt.h new file mode 100644 index 0000000000..53c48af4ec --- /dev/null +++ b/core/fpdfdoc/pdf_vt.h @@ -0,0 +1,554 @@ +// 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 + +#ifndef CORE_FPDFDOC_PDF_VT_H_ +#define CORE_FPDFDOC_PDF_VT_H_ + +#include "core/include/fpdfdoc/fpdf_vt.h" + +class CPDF_VariableText; +class CPDF_VariableText_Iterator; + +#define IsFloatZero(f) ((f) < 0.0001 && (f) > -0.0001) +#define IsFloatBigger(fa, fb) ((fa) > (fb) && !IsFloatZero((fa) - (fb))) +#define IsFloatSmaller(fa, fb) ((fa) < (fb) && !IsFloatZero((fa) - (fb))) + +class CPVT_Size { + public: + CPVT_Size() : x(0.0f), y(0.0f) {} + CPVT_Size(FX_FLOAT other_x, FX_FLOAT other_y) { + x = other_x; + y = other_y; + } + FX_FLOAT x, y; +}; +class CPVT_FloatRect : public CFX_FloatRect { + public: + CPVT_FloatRect() { left = top = right = bottom = 0.0f; } + CPVT_FloatRect(FX_FLOAT other_left, + FX_FLOAT other_top, + FX_FLOAT other_right, + FX_FLOAT other_bottom) { + left = other_left; + top = other_top; + right = other_right; + bottom = other_bottom; + } + explicit CPVT_FloatRect(const CFX_FloatRect& rect) { + left = rect.left; + top = rect.top; + right = rect.right; + bottom = rect.bottom; + } + void Default() { left = top = right = bottom = 0.0f; } + FX_FLOAT Height() const { + if (top > bottom) + return top - bottom; + return bottom - top; + } +}; +struct CPVT_SectionInfo { + CPVT_SectionInfo() + : rcSection(), nTotalLine(0), pSecProps(NULL), pWordProps(NULL) {} + virtual ~CPVT_SectionInfo() { + delete pSecProps; + delete pWordProps; + } + CPVT_SectionInfo(const CPVT_SectionInfo& other) + : rcSection(), nTotalLine(0), pSecProps(NULL), pWordProps(NULL) { + operator=(other); + } + void operator=(const CPVT_SectionInfo& other) { + if (this == &other) { + return; + } + rcSection = other.rcSection; + nTotalLine = other.nTotalLine; + if (other.pSecProps) { + if (pSecProps) { + *pSecProps = *other.pSecProps; + } else { + pSecProps = new CPVT_SecProps(*other.pSecProps); + } + } + if (other.pWordProps) { + if (pWordProps) { + *pWordProps = *other.pWordProps; + } else { + pWordProps = new CPVT_WordProps(*other.pWordProps); + } + } + } + CPVT_FloatRect rcSection; + int32_t nTotalLine; + CPVT_SecProps* pSecProps; + CPVT_WordProps* pWordProps; +}; +struct CPVT_LineInfo { + CPVT_LineInfo() + : nTotalWord(0), + nBeginWordIndex(-1), + nEndWordIndex(-1), + fLineX(0.0f), + fLineY(0.0f), + fLineWidth(0.0f), + fLineAscent(0.0f), + fLineDescent(0.0f) {} + int32_t nTotalWord; + int32_t nBeginWordIndex; + int32_t nEndWordIndex; + FX_FLOAT fLineX; + FX_FLOAT fLineY; + FX_FLOAT fLineWidth; + FX_FLOAT fLineAscent; + FX_FLOAT fLineDescent; +}; +struct CPVT_WordInfo { + CPVT_WordInfo() + : Word(0), + nCharset(0), + fWordX(0.0f), + fWordY(0.0f), + fWordTail(0.0f), + nFontIndex(-1), + pWordProps(NULL) {} + CPVT_WordInfo(FX_WORD word, + int32_t charset, + int32_t fontIndex, + CPVT_WordProps* pProps) + : Word(word), + nCharset(charset), + fWordX(0.0f), + fWordY(0.0f), + fWordTail(0.0f), + nFontIndex(fontIndex), + pWordProps(pProps) {} + virtual ~CPVT_WordInfo() { delete pWordProps; } + CPVT_WordInfo(const CPVT_WordInfo& word) + : Word(0), + nCharset(0), + fWordX(0.0f), + fWordY(0.0f), + fWordTail(0.0f), + nFontIndex(-1), + pWordProps(NULL) { + operator=(word); + } + void operator=(const CPVT_WordInfo& word) { + if (this == &word) { + return; + } + Word = word.Word; + nCharset = word.nCharset; + nFontIndex = word.nFontIndex; + if (word.pWordProps) { + if (pWordProps) { + *pWordProps = *word.pWordProps; + } else { + pWordProps = new CPVT_WordProps(*word.pWordProps); + } + } + } + FX_WORD Word; + int32_t nCharset; + FX_FLOAT fWordX; + FX_FLOAT fWordY; + FX_FLOAT fWordTail; + int32_t nFontIndex; + CPVT_WordProps* pWordProps; +}; +struct CPVT_FloatRange { + CPVT_FloatRange() : fMin(0.0f), fMax(0.0f) {} + CPVT_FloatRange(FX_FLOAT min, FX_FLOAT max) : fMin(min), fMax(max) {} + FX_FLOAT Range() const { return fMax - fMin; } + FX_FLOAT fMin, fMax; +}; +template <class TYPE> +class CPVT_ArrayTemplate : public CFX_ArrayTemplate<TYPE> { + public: + FX_BOOL IsEmpty() { return CFX_ArrayTemplate<TYPE>::GetSize() <= 0; } + TYPE GetAt(int nIndex) const { + if (nIndex >= 0 && nIndex < CFX_ArrayTemplate<TYPE>::GetSize()) { + return CFX_ArrayTemplate<TYPE>::GetAt(nIndex); + } + return NULL; + } + void RemoveAt(int nIndex) { + if (nIndex >= 0 && nIndex < CFX_ArrayTemplate<TYPE>::GetSize()) { + CFX_ArrayTemplate<TYPE>::RemoveAt(nIndex); + } + } +}; +class CLine { + public: + CLine(); + virtual ~CLine(); + CPVT_WordPlace GetBeginWordPlace() const; + CPVT_WordPlace GetEndWordPlace() const; + CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const; + CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const; + CPVT_WordPlace LinePlace; + CPVT_LineInfo m_LineInfo; +}; +class CLines { + public: + CLines() : m_nTotal(0) {} + virtual ~CLines() { RemoveAll(); } + int32_t GetSize() const { return m_Lines.GetSize(); } + CLine* GetAt(int32_t nIndex) const { return m_Lines.GetAt(nIndex); } + void Empty() { m_nTotal = 0; } + void RemoveAll() { + for (int32_t i = 0, sz = GetSize(); i < sz; i++) { + delete GetAt(i); + } + m_Lines.RemoveAll(); + m_nTotal = 0; + } + int32_t Add(const CPVT_LineInfo& lineinfo) { + if (m_nTotal >= GetSize()) { + CLine* pLine = new CLine; + pLine->m_LineInfo = lineinfo; + m_Lines.Add(pLine); + } else if (CLine* pLine = GetAt(m_nTotal)) { + pLine->m_LineInfo = lineinfo; + } + return m_nTotal++; + } + void Clear() { + for (int32_t i = GetSize() - 1; i >= m_nTotal; i--) { + delete GetAt(i); + m_Lines.RemoveAt(i); + } + } + + private: + CPVT_ArrayTemplate<CLine*> m_Lines; + int32_t m_nTotal; +}; +class CSection { + friend class CTypeset; + + public: + explicit CSection(CPDF_VariableText* pVT); + virtual ~CSection(); + void ResetAll(); + void ResetLineArray(); + void ResetWordArray(); + void ResetLinePlace(); + CPVT_WordPlace AddWord(const CPVT_WordPlace& place, + const CPVT_WordInfo& wordinfo); + CPVT_WordPlace AddLine(const CPVT_LineInfo& lineinfo); + void ClearWords(const CPVT_WordRange& PlaceRange); + void ClearWord(const CPVT_WordPlace& place); + CPVT_FloatRect Rearrange(); + CPVT_Size GetSectionSize(FX_FLOAT fFontSize); + CPVT_WordPlace GetBeginWordPlace() const; + CPVT_WordPlace GetEndWordPlace() const; + CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const; + CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const; + void UpdateWordPlace(CPVT_WordPlace& place) const; + CPVT_WordPlace SearchWordPlace(const CFX_FloatPoint& point) const; + CPVT_WordPlace SearchWordPlace(FX_FLOAT fx, + const CPVT_WordPlace& lineplace) const; + CPVT_WordPlace SearchWordPlace(FX_FLOAT fx, + const CPVT_WordRange& range) const; + + public: + CPVT_WordPlace SecPlace; + CPVT_SectionInfo m_SecInfo; + CLines m_LineArray; + CPVT_ArrayTemplate<CPVT_WordInfo*> m_WordArray; + + private: + void ClearLeftWords(int32_t nWordIndex); + void ClearRightWords(int32_t nWordIndex); + void ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex); + + CPDF_VariableText* m_pVT; +}; +class CTypeset { + public: + explicit CTypeset(CSection* pSection); + virtual ~CTypeset(); + CPVT_Size GetEditSize(FX_FLOAT fFontSize); + CPVT_FloatRect Typeset(); + CPVT_FloatRect CharArray(); + + private: + void SplitLines(FX_BOOL bTypeset, FX_FLOAT fFontSize); + void OutputLines(); + + CPVT_FloatRect m_rcRet; + CPDF_VariableText* m_pVT; + CSection* m_pSection; +}; +class CPDF_EditContainer { + public: + CPDF_EditContainer() : m_rcPlate(0, 0, 0, 0), m_rcContent(0, 0, 0, 0) {} + virtual ~CPDF_EditContainer() {} + virtual void SetPlateRect(const CFX_FloatRect& rect) { m_rcPlate = rect; } + virtual const CFX_FloatRect& GetPlateRect() const { return m_rcPlate; } + virtual void SetContentRect(const CPVT_FloatRect& rect) { + m_rcContent = rect; + } + virtual CFX_FloatRect GetContentRect() const { return m_rcContent; } + FX_FLOAT GetPlateWidth() const { return m_rcPlate.right - m_rcPlate.left; } + FX_FLOAT GetPlateHeight() const { return m_rcPlate.top - m_rcPlate.bottom; } + CPVT_Size GetPlateSize() const { + return CPVT_Size(GetPlateWidth(), GetPlateHeight()); + } + CFX_FloatPoint GetBTPoint() const { + return CFX_FloatPoint(m_rcPlate.left, m_rcPlate.top); + } + CFX_FloatPoint GetETPoint() const { + return CFX_FloatPoint(m_rcPlate.right, m_rcPlate.bottom); + } + inline CFX_FloatPoint InToOut(const CFX_FloatPoint& point) const { + return CFX_FloatPoint(point.x + GetBTPoint().x, GetBTPoint().y - point.y); + } + inline CFX_FloatPoint OutToIn(const CFX_FloatPoint& point) const { + return CFX_FloatPoint(point.x - GetBTPoint().x, GetBTPoint().y - point.y); + } + inline CFX_FloatRect InToOut(const CPVT_FloatRect& rect) const { + CFX_FloatPoint ptLeftTop = InToOut(CFX_FloatPoint(rect.left, rect.top)); + CFX_FloatPoint ptRightBottom = + InToOut(CFX_FloatPoint(rect.right, rect.bottom)); + return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x, + ptLeftTop.y); + } + inline CPVT_FloatRect OutToIn(const CFX_FloatRect& rect) const { + CFX_FloatPoint ptLeftTop = OutToIn(CFX_FloatPoint(rect.left, rect.top)); + CFX_FloatPoint ptRightBottom = + OutToIn(CFX_FloatPoint(rect.right, rect.bottom)); + return CPVT_FloatRect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x, + ptRightBottom.y); + } + + private: + CFX_FloatRect m_rcPlate; + CPVT_FloatRect m_rcContent; +}; + +class CPDF_VariableText : public IPDF_VariableText, private CPDF_EditContainer { + friend class CTypeset; + friend class CSection; + friend class CPDF_VariableText_Iterator; + + public: + CPDF_VariableText(); + ~CPDF_VariableText() override; + + // IPDF_VariableText + IPDF_VariableText_Provider* SetProvider( + IPDF_VariableText_Provider* pProvider) override; + IPDF_VariableText_Iterator* GetIterator() override; + void SetPlateRect(const CFX_FloatRect& rect) override { + CPDF_EditContainer::SetPlateRect(rect); + } + void SetAlignment(int32_t nFormat = 0) override { m_nAlignment = nFormat; } + void SetPasswordChar(FX_WORD wSubWord = '*') override { + m_wSubWord = wSubWord; + } + void SetLimitChar(int32_t nLimitChar = 0) override { + m_nLimitChar = nLimitChar; + } + void SetCharSpace(FX_FLOAT fCharSpace = 0.0f) override { + m_fCharSpace = fCharSpace; + } + void SetHorzScale(int32_t nHorzScale = 100) override { + m_nHorzScale = nHorzScale; + } + void SetMultiLine(FX_BOOL bMultiLine = TRUE) override { + m_bMultiLine = bMultiLine; + } + void SetAutoReturn(FX_BOOL bAuto = TRUE) override { m_bLimitWidth = bAuto; } + void SetFontSize(FX_FLOAT fFontSize) override { m_fFontSize = fFontSize; } + void SetCharArray(int32_t nCharArray = 0) override { + m_nCharArray = nCharArray; + } + void SetAutoFontSize(FX_BOOL bAuto = TRUE) override { + m_bAutoFontSize = bAuto; + } + void SetRichText(FX_BOOL bRichText) override { m_bRichText = bRichText; } + void SetLineLeading(FX_FLOAT fLineLeading) override { + m_fLineLeading = fLineLeading; + } + void Initialize() override; + FX_BOOL IsValid() const override { return m_bInitial; } + FX_BOOL IsRichText() const override { return m_bRichText; } + void RearrangeAll() override; + void RearrangePart(const CPVT_WordRange& PlaceRange) override; + void ResetAll() override; + void SetText(const FX_WCHAR* text, + int32_t charset = 1, + const CPVT_SecProps* pSecProps = NULL, + const CPVT_WordProps* pWordProps = NULL) override; + CPVT_WordPlace InsertWord(const CPVT_WordPlace& place, + FX_WORD word, + int32_t charset = 1, + const CPVT_WordProps* pWordProps = NULL) override; + CPVT_WordPlace InsertSection( + const CPVT_WordPlace& place, + const CPVT_SecProps* pSecProps = NULL, + const CPVT_WordProps* pWordProps = NULL) override; + CPVT_WordPlace InsertText(const CPVT_WordPlace& place, + const FX_WCHAR* text, + int32_t charset = 1, + const CPVT_SecProps* pSecProps = NULL, + const CPVT_WordProps* pWordProps = NULL) override; + CPVT_WordPlace DeleteWords(const CPVT_WordRange& PlaceRange) override; + CPVT_WordPlace DeleteWord(const CPVT_WordPlace& place) override; + CPVT_WordPlace BackSpaceWord(const CPVT_WordPlace& place) override; + const CFX_FloatRect& GetPlateRect() const override { + return CPDF_EditContainer::GetPlateRect(); + } + CFX_FloatRect GetContentRect() const override; + int32_t GetTotalWords() const override; + FX_FLOAT GetFontSize() const override { return m_fFontSize; } + int32_t GetAlignment() const override { return m_nAlignment; } + FX_WORD GetPasswordChar() const override { return GetSubWord(); } + int32_t GetCharArray() const override { return m_nCharArray; } + int32_t GetLimitChar() const override { return m_nLimitChar; } + FX_BOOL IsMultiLine() const override { return m_bMultiLine; } + int32_t GetHorzScale() const override { return m_nHorzScale; } + FX_FLOAT GetCharSpace() const override { return m_fCharSpace; } + CPVT_WordPlace GetBeginWordPlace() const override; + CPVT_WordPlace GetEndWordPlace() const override; + CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const override; + CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const override; + CPVT_WordPlace SearchWordPlace(const CFX_FloatPoint& point) const override; + CPVT_WordPlace GetUpWordPlace(const CPVT_WordPlace& place, + const CFX_FloatPoint& point) const override; + CPVT_WordPlace GetDownWordPlace(const CPVT_WordPlace& place, + const CFX_FloatPoint& point) const override; + CPVT_WordPlace GetLineBeginPlace(const CPVT_WordPlace& place) const override; + CPVT_WordPlace GetLineEndPlace(const CPVT_WordPlace& place) const override; + CPVT_WordPlace GetSectionBeginPlace( + const CPVT_WordPlace& place) const override; + CPVT_WordPlace GetSectionEndPlace(const CPVT_WordPlace& place) const override; + void UpdateWordPlace(CPVT_WordPlace& place) const override; + CPVT_WordPlace AdjustLineHeader(const CPVT_WordPlace& place, + FX_BOOL bPrevOrNext) const override; + int32_t WordPlaceToWordIndex(const CPVT_WordPlace& place) const override; + CPVT_WordPlace WordIndexToWordPlace(int32_t index) const override; + + FX_WORD GetSubWord() const { return m_wSubWord; } + + private: + int32_t GetCharWidth(int32_t nFontIndex, + FX_WORD Word, + FX_WORD SubWord, + int32_t nWordStyle); + int32_t GetTypeAscent(int32_t nFontIndex); + int32_t GetTypeDescent(int32_t nFontIndex); + int32_t GetWordFontIndex(FX_WORD word, int32_t charset, int32_t nFontIndex); + int32_t GetDefaultFontIndex(); + FX_BOOL IsLatinWord(FX_WORD word); + + CPVT_WordPlace AddSection(const CPVT_WordPlace& place, + const CPVT_SectionInfo& secinfo); + CPVT_WordPlace AddLine(const CPVT_WordPlace& place, + const CPVT_LineInfo& lineinfo); + CPVT_WordPlace AddWord(const CPVT_WordPlace& place, + const CPVT_WordInfo& wordinfo); + FX_BOOL GetWordInfo(const CPVT_WordPlace& place, CPVT_WordInfo& wordinfo); + FX_BOOL SetWordInfo(const CPVT_WordPlace& place, + const CPVT_WordInfo& wordinfo); + FX_BOOL GetLineInfo(const CPVT_WordPlace& place, CPVT_LineInfo& lineinfo); + FX_BOOL GetSectionInfo(const CPVT_WordPlace& place, + CPVT_SectionInfo& secinfo); + FX_FLOAT GetWordFontSize(const CPVT_WordInfo& WordInfo, + FX_BOOL bFactFontSize = FALSE); + FX_FLOAT GetWordWidth(int32_t nFontIndex, + FX_WORD Word, + FX_WORD SubWord, + FX_FLOAT fCharSpace, + int32_t nHorzScale, + FX_FLOAT fFontSize, + FX_FLOAT fWordTail, + int32_t nWordStyle); + FX_FLOAT GetWordWidth(const CPVT_WordInfo& WordInfo); + FX_FLOAT GetWordAscent(const CPVT_WordInfo& WordInfo, FX_FLOAT fFontSize); + FX_FLOAT GetWordDescent(const CPVT_WordInfo& WordInfo, FX_FLOAT fFontSize); + FX_FLOAT GetWordAscent(const CPVT_WordInfo& WordInfo, + FX_BOOL bFactFontSize = FALSE); + FX_FLOAT GetWordDescent(const CPVT_WordInfo& WordInfo, + FX_BOOL bFactFontSize = FALSE); + FX_FLOAT GetLineAscent(const CPVT_SectionInfo& SecInfo); + FX_FLOAT GetLineDescent(const CPVT_SectionInfo& SecInfo); + FX_FLOAT GetFontAscent(int32_t nFontIndex, FX_FLOAT fFontSize); + FX_FLOAT GetFontDescent(int32_t nFontIndex, FX_FLOAT fFontSize); + int32_t GetWordFontIndex(const CPVT_WordInfo& WordInfo); + FX_FLOAT GetCharSpace(const CPVT_WordInfo& WordInfo); + int32_t GetHorzScale(const CPVT_WordInfo& WordInfo); + FX_FLOAT GetLineLeading(const CPVT_SectionInfo& SecInfo); + FX_FLOAT GetLineIndent(const CPVT_SectionInfo& SecInfo); + int32_t GetAlignment(const CPVT_SectionInfo& SecInfo); + + void ClearSectionRightWords(const CPVT_WordPlace& place); + + FX_BOOL ClearEmptySection(const CPVT_WordPlace& place); + void ClearEmptySections(const CPVT_WordRange& PlaceRange); + void LinkLatterSection(const CPVT_WordPlace& place); + void ClearWords(const CPVT_WordRange& PlaceRange); + CPVT_WordPlace ClearLeftWord(const CPVT_WordPlace& place); + CPVT_WordPlace ClearRightWord(const CPVT_WordPlace& place); + + private: + CPVT_FloatRect Rearrange(const CPVT_WordRange& PlaceRange); + FX_FLOAT GetAutoFontSize(); + FX_BOOL IsBigger(FX_FLOAT fFontSize); + CPVT_FloatRect RearrangeSections(const CPVT_WordRange& PlaceRange); + + void ResetSectionArray(); + + CPVT_ArrayTemplate<CSection*> m_SectionArray; + int32_t m_nLimitChar; + int32_t m_nCharArray; + FX_BOOL m_bMultiLine; + FX_BOOL m_bLimitWidth; + FX_BOOL m_bAutoFontSize; + int32_t m_nAlignment; + FX_FLOAT m_fLineLeading; + FX_FLOAT m_fCharSpace; + int32_t m_nHorzScale; + FX_WORD m_wSubWord; + FX_FLOAT m_fFontSize; + + private: + FX_BOOL m_bInitial; + FX_BOOL m_bRichText; + IPDF_VariableText_Provider* m_pVTProvider; + CPDF_VariableText_Iterator* m_pVTIterator; +}; + +class CPDF_VariableText_Iterator : public IPDF_VariableText_Iterator { + public: + explicit CPDF_VariableText_Iterator(CPDF_VariableText* pVT); + ~CPDF_VariableText_Iterator() override; + + // IPDF_VariableText_Iterator + FX_BOOL NextWord() override; + FX_BOOL PrevWord() override; + FX_BOOL NextLine() override; + FX_BOOL PrevLine() override; + FX_BOOL NextSection() override; + FX_BOOL PrevSection() override; + FX_BOOL SetWord(const CPVT_Word& word) override; + FX_BOOL GetWord(CPVT_Word& word) const override; + FX_BOOL GetLine(CPVT_Line& line) const override; + FX_BOOL GetSection(CPVT_Section& section) const override; + FX_BOOL SetSection(const CPVT_Section& section) override; + void SetAt(int32_t nWordIndex) override; + void SetAt(const CPVT_WordPlace& place) override; + const CPVT_WordPlace& GetAt() const override { return m_CurPos; } + + private: + CPVT_WordPlace m_CurPos; + CPDF_VariableText* m_pVT; +}; + +#endif // CORE_FPDFDOC_PDF_VT_H_ diff --git a/core/fpdfdoc/tagged_int.h b/core/fpdfdoc/tagged_int.h new file mode 100644 index 0000000000..e930f613b1 --- /dev/null +++ b/core/fpdfdoc/tagged_int.h @@ -0,0 +1,106 @@ +// 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 + +#ifndef CORE_FPDFDOC_TAGGED_INT_H_ +#define CORE_FPDFDOC_TAGGED_INT_H_ + +#include <map> + +#include "core/include/fpdfdoc/fpdf_tagged.h" + +class CPDF_StructElementImpl; + +class CPDF_StructTreeImpl : public CPDF_StructTree { + public: + explicit CPDF_StructTreeImpl(const CPDF_Document* pDoc); + ~CPDF_StructTreeImpl() override; + + // CPDF_StructTree + int CountTopElements() const override { return m_Kids.GetSize(); } + CPDF_StructElement* GetTopElement(int i) const override { + return (CPDF_StructElement*)m_Kids.GetAt(i); + } + + void LoadDocTree(); + void LoadPageTree(const CPDF_Dictionary* pPageDict); + CPDF_StructElementImpl* AddPageNode( + CPDF_Dictionary* pElement, + std::map<CPDF_Dictionary*, CPDF_StructElementImpl*>& map, + int nLevel = 0); + FX_BOOL AddTopLevelNode(CPDF_Dictionary* pDict, + CPDF_StructElementImpl* pElement); + + protected: + const CPDF_Dictionary* m_pTreeRoot; + const CPDF_Dictionary* m_pRoleMap; + const CPDF_Dictionary* m_pPage; + CFX_ArrayTemplate<CPDF_StructElementImpl*> m_Kids; + friend class CPDF_StructElementImpl; +}; + +class CPDF_StructElementImpl final : public CPDF_StructElement { + public: + CPDF_StructElementImpl(CPDF_StructTreeImpl* pTree, + CPDF_StructElementImpl* pParent, + CPDF_Dictionary* pDict); + + // CPDF_StructTreeImpl + CPDF_StructTree* GetTree() const override { return m_pTree; } + const CFX_ByteString& GetType() const override { return m_Type; } + CPDF_StructElement* GetParent() const override { return m_pParent; } + CPDF_Dictionary* GetDict() const override { return m_pDict; } + int CountKids() const override { return m_Kids.GetSize(); } + const CPDF_StructKid& GetKid(int index) const override { + return m_Kids.GetData()[index]; + } + CPDF_Object* GetAttr(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_BOOL bInheritable = FALSE, + FX_FLOAT fLevel = 0.0F) override; + CFX_ByteString GetName(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + const CFX_ByteStringC& default_value, + FX_BOOL bInheritable = FALSE, + int subindex = -1) override; + FX_ARGB GetColor(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_ARGB default_value, + FX_BOOL bInheritable = FALSE, + int subindex = -1) override; + FX_FLOAT GetNumber(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_FLOAT default_value, + FX_BOOL bInheritable = FALSE, + int subindex = -1) override; + int GetInteger(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + int default_value, + FX_BOOL bInheritable = FALSE, + int subindex = -1) override; + + void LoadKids(CPDF_Dictionary* pDict); + void LoadKid(FX_DWORD PageObjNum, CPDF_Object* pObj, CPDF_StructKid* pKid); + CPDF_Object* GetAttr(const CFX_ByteStringC& owner, + const CFX_ByteStringC& name, + FX_BOOL bInheritable, + int subindex); + CPDF_StructElementImpl* Retain(); + void Release(); + + protected: + ~CPDF_StructElementImpl() override; + + CPDF_StructTreeImpl* m_pTree; + CFX_ByteString m_Type; + CPDF_StructElementImpl* m_pParent; + CPDF_Dictionary* m_pDict; + CFX_ArrayTemplate<CPDF_StructKid> m_Kids; + int m_RefCount; + + friend class CPDF_StructTreeImpl; +}; + +#endif // CORE_FPDFDOC_TAGGED_INT_H_ |