summaryrefslogtreecommitdiff
path: root/core/fpdfdoc
diff options
context:
space:
mode:
authorjaepark <jaepark@google.com>2016-08-29 17:15:08 -0700
committerCommit bot <commit-bot@chromium.org>2016-08-29 17:15:08 -0700
commit35512aa7e4acc3ceb9c6aef5d61eebfb4ae802af (patch)
tree18ad1447ba8a7d06f304e1418616d919eadbbf8c /core/fpdfdoc
parent07f5fd57682700bcbba20f01d52a806676fd02ff (diff)
downloadpdfium-35512aa7e4acc3ceb9c6aef5d61eebfb4ae802af.tar.xz
Display content of the annotation when mouse hover.
Each annotation has its contents, and users should be able to see the contents. In this patch, PDFium creates a Popup annotation for each annotation and stores the author and the content. When a user mouse hover on the annotation, PDFium draws the corresponding Popup annotation and displays the content. Also, roll DEPS for testing/corpus to 5867fa6. BUG=62625 Review-Url: https://codereview.chromium.org/2273893002
Diffstat (limited to 'core/fpdfdoc')
-rw-r--r--core/fpdfdoc/cpdf_annot.cpp9
-rw-r--r--core/fpdfdoc/cpdf_annotlist.cpp48
-rw-r--r--core/fpdfdoc/cpvt_generateap.cpp142
-rw-r--r--core/fpdfdoc/cpvt_generateap.h1
-rw-r--r--core/fpdfdoc/include/cpdf_annot.h8
5 files changed, 193 insertions, 15 deletions
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp
index 10360eaf68..e79acab7a0 100644
--- a/core/fpdfdoc/cpdf_annot.cpp
+++ b/core/fpdfdoc/cpdf_annot.cpp
@@ -21,7 +21,9 @@
CPDF_Annot::CPDF_Annot(CPDF_Dictionary* pDict, CPDF_Document* pDocument)
: m_pAnnotDict(pDict),
m_pDocument(pDocument),
- m_sSubtype(m_pAnnotDict->GetStringBy("Subtype")) {
+ m_sSubtype(m_pAnnotDict->GetStringBy("Subtype")),
+ m_bOpenState(false),
+ m_pPopupAnnot(nullptr) {
GenerateAPIfNeeded();
}
@@ -36,6 +38,8 @@ void CPDF_Annot::GenerateAPIfNeeded() {
CPVT_GenerateAP::GenerateHighlightAP(m_pDocument, m_pAnnotDict);
else if (m_sSubtype == "Ink")
CPVT_GenerateAP::GenerateInkAP(m_pDocument, m_pAnnotDict);
+ else if (m_sSubtype == "Popup")
+ CPVT_GenerateAP::GeneratePopupAP(m_pDocument, m_pAnnotDict);
else if (m_sSubtype == "Square")
CPVT_GenerateAP::GenerateSquareAP(m_pDocument, m_pAnnotDict);
else if (m_sSubtype == "Squiggly")
@@ -152,6 +156,9 @@ FX_BOOL CPDF_Annot::DrawAppearance(CPDF_Page* pPage,
if (IsAnnotationHidden(m_pAnnotDict))
return FALSE;
+ if (m_sSubtype == "Popup" && !m_bOpenState)
+ return FALSE;
+
// It might happen that by the time this annotation instance was created,
// it was flagged as "hidden" (e.g. /F 2), and hence CPVT_GenerateAP decided
// to not "generate" its AP.
diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp
index e6c93c1d1e..4c569892c2 100644
--- a/core/fpdfdoc/cpdf_annotlist.cpp
+++ b/core/fpdfdoc/cpdf_annotlist.cpp
@@ -16,6 +16,40 @@
#include "core/fpdfdoc/include/cpdf_occontext.h"
#include "core/fxge/include/cfx_renderdevice.h"
+namespace {
+
+std::unique_ptr<CPDF_Annot> CreatePopupAnnot(CPDF_Annot* pAnnot,
+ CPDF_Document* pDocument) {
+ CPDF_Dictionary* pParentDict = pAnnot->GetAnnotDict();
+ if (!pParentDict)
+ return std::unique_ptr<CPDF_Annot>();
+
+ CFX_ByteString sContents = pParentDict->GetStringBy("Contents");
+ if (sContents.IsEmpty())
+ return std::unique_ptr<CPDF_Annot>();
+
+ CPDF_Dictionary* pAnnotDict = new CPDF_Dictionary;
+ pAnnotDict->SetAtName("Type", "Annot");
+ pAnnotDict->SetAtName("Subtype", "Popup");
+ pAnnotDict->SetAtString("T", pParentDict->GetStringBy("T"));
+ pAnnotDict->SetAtString("Contents", sContents);
+
+ CFX_FloatRect rect = pParentDict->GetRectBy("Rect");
+ rect.Normalize();
+ CFX_FloatRect popupRect(0, 0, 200, 200);
+ popupRect.Translate(rect.left, rect.bottom - popupRect.Height());
+
+ pAnnotDict->SetAtRect("Rect", popupRect);
+ pAnnotDict->SetAtInteger("F", 0);
+
+ std::unique_ptr<CPDF_Annot> pPopupAnnot(
+ new CPDF_Annot(pAnnotDict, pDocument));
+ pAnnot->SetPopupAnnot(pPopupAnnot.get());
+ return pPopupAnnot;
+}
+
+} // namespace
+
CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage)
: m_pDocument(pPage->m_pDocument) {
if (!pPage->m_pFormDict)
@@ -42,6 +76,12 @@ CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage)
pAnnots->RemoveAt(i + 1);
pDict = pAnnots->GetDictAt(i);
}
+
+ // Skip creating Popup annotation in the PDF document since PDFium provides
+ // its own Popup annotations.
+ if (pDict->GetStringBy("Subtype") == "Popup")
+ continue;
+
m_AnnotList.push_back(
std::unique_ptr<CPDF_Annot>(new CPDF_Annot(pDict, m_pDocument)));
if (bRegenerateAP && pDict->GetStringBy("Subtype") == "Widget" &&
@@ -49,6 +89,14 @@ CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage)
FPDF_GenerateAP(m_pDocument, pDict);
}
}
+
+ size_t nAnnotListSize = m_AnnotList.size();
+ for (size_t i = 0; i < nAnnotListSize; ++i) {
+ std::unique_ptr<CPDF_Annot> pPopupAnnot(
+ CreatePopupAnnot(m_AnnotList[i].get(), m_pDocument));
+ if (pPopupAnnot)
+ m_AnnotList.push_back(std::move(pPopupAnnot));
+ }
}
CPDF_AnnotList::~CPDF_AnnotList() {}
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 12ba4ef295..d19992ec60 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -509,6 +509,42 @@ CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) {
return sDashStream.MakeString();
}
+CFX_ByteString GetPopupContentsString(CPDF_Document* pDoc,
+ const CPDF_Dictionary& pAnnotDict,
+ CPDF_Font* pDefFont,
+ const CFX_ByteString& sFontName) {
+ CFX_WideString swValue(pAnnotDict.GetUnicodeTextBy("T"));
+ swValue += L'\n';
+ swValue += pAnnotDict.GetUnicodeTextBy("Contents");
+ CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName);
+
+ CPDF_VariableText::Provider prd(&map);
+ CPDF_VariableText vt;
+ vt.SetProvider(&prd);
+ vt.SetPlateRect(pAnnotDict.GetRectBy("Rect"));
+ vt.SetFontSize(12);
+ vt.SetAutoReturn(TRUE);
+ vt.SetMultiLine(TRUE);
+
+ vt.Initialize();
+ vt.SetText(swValue.c_str());
+ vt.RearrangeAll();
+ CFX_FloatPoint ptOffset(3.0f, -3.0f);
+ CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP(
+ &map, vt.GetIterator(), ptOffset, FALSE, 0);
+
+ if (sContent.IsEmpty())
+ return CFX_ByteString();
+
+ CFX_ByteTextBuf sAppStream;
+ sAppStream << "BT\n"
+ << CPVT_GenerateAP::GenerateColorAP(
+ CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::FILL)
+ << sContent << "ET\n"
+ << "Q\n";
+ return sAppStream.MakeString();
+}
+
CPDF_Dictionary* GenerateExtGStateDict(const CPDF_Dictionary& pAnnotDict,
const CFX_ByteString& sExtGSDictName,
const CFX_ByteString& sBlendMode) {
@@ -528,11 +564,39 @@ CPDF_Dictionary* GenerateExtGStateDict(const CPDF_Dictionary& pAnnotDict,
return pExtGStateDict;
}
-// Takes ownership of |pExtGStateDict|.
+CPDF_Dictionary* GenerateResourceFontDict(CPDF_Document* pDoc,
+ const CFX_ByteString& sFontDictName) {
+ CPDF_Dictionary* pFontDict = new CPDF_Dictionary;
+ pFontDict->SetAtName("Type", "Font");
+ pFontDict->SetAtName("Subtype", "Type1");
+ pFontDict->SetAtName("BaseFont", "Helvetica");
+ pFontDict->SetAtName("Encoding", "WinAnsiEncoding");
+ pDoc->AddIndirectObject(pFontDict);
+
+ CPDF_Dictionary* pResourceFontDict = new CPDF_Dictionary;
+ pResourceFontDict->SetAtReference(sFontDictName, pDoc, pFontDict);
+
+ return pResourceFontDict;
+}
+
+// Takes ownership of |pExtGStateDict| and |pResourceFontDict|.
+CPDF_Dictionary* GenerateResourceDict(CPDF_Dictionary* pExtGStateDict,
+ CPDF_Dictionary* pResourceFontDict) {
+ CPDF_Dictionary* pResourceDict = new CPDF_Dictionary;
+ if (pExtGStateDict)
+ pResourceDict->SetAt("ExtGState", pExtGStateDict);
+
+ if (pResourceFontDict)
+ pResourceDict->SetAt("Font", pResourceFontDict);
+
+ return pResourceDict;
+}
+
+// Takes ownership of |pResourceDict|.
void GenerateAndSetAPDict(CPDF_Document* pDoc,
CPDF_Dictionary* pAnnotDict,
const CFX_ByteTextBuf& sAppStream,
- CPDF_Dictionary* pExtGStateDict) {
+ CPDF_Dictionary* pResourceDict) {
CPDF_Dictionary* pAPDict = new CPDF_Dictionary;
pAnnotDict->SetAt("AP", pAPDict);
@@ -551,9 +615,6 @@ void GenerateAndSetAPDict(CPDF_Document* pDoc,
CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect");
pStreamDict->SetAtRect("BBox", rect);
- CPDF_Dictionary* pResourceDict = new CPDF_Dictionary;
- pResourceDict->SetAt("ExtGState", pExtGStateDict);
-
pStreamDict->SetAt("Resources", pResourceDict);
}
@@ -742,7 +803,9 @@ bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -769,7 +832,9 @@ bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -824,7 +889,9 @@ bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -847,8 +914,9 @@ bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
-
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -875,7 +943,47 @@ bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
+ return true;
+}
+
+bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc,
+ CPDF_Dictionary* pAnnotDict) {
+ CFX_ByteTextBuf sAppStream;
+ CFX_ByteString sExtGSDictName = "GS";
+ sAppStream << "/" << sExtGSDictName << " gs\n";
+
+ sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 1, 1, 0),
+ PaintOperation::FILL);
+ sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 0, 0, 0),
+ PaintOperation::STROKE);
+
+ const FX_FLOAT fBorderWidth = 1;
+ sAppStream << fBorderWidth << " w\n";
+
+ CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect");
+ rect.Normalize();
+ rect.Deflate(fBorderWidth / 2, fBorderWidth / 2);
+
+ sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " "
+ << rect.Height() << " re b\n";
+
+ CFX_ByteString sFontName = "FONT";
+ CPDF_Dictionary* pExtGStateDict =
+ GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
+ CPDF_Dictionary* pResourceFontDict =
+ GenerateResourceFontDict(pDoc, sFontName);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pResourceFontDict, pExtGStateDict);
+
+ CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict);
+ if (!pDefFont)
+ return false;
+
+ sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -923,7 +1031,9 @@ bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -972,7 +1082,9 @@ bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
@@ -999,7 +1111,9 @@ bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc,
CPDF_Dictionary* pExtGStateDict =
GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
- GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict);
+ CPDF_Dictionary* pResourceDict =
+ GenerateResourceDict(pExtGStateDict, nullptr);
+ GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pResourceDict);
return true;
}
diff --git a/core/fpdfdoc/cpvt_generateap.h b/core/fpdfdoc/cpvt_generateap.h
index 062acf684b..3fbc4cc591 100644
--- a/core/fpdfdoc/cpvt_generateap.h
+++ b/core/fpdfdoc/cpvt_generateap.h
@@ -34,6 +34,7 @@ class CPVT_GenerateAP {
static bool GenerateInkAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
static bool GenerateListBoxAP(CPDF_Document* pDoc,
CPDF_Dictionary* pAnnotDict);
+ static bool GeneratePopupAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict);
static bool GenerateSquareAP(CPDF_Document* pDoc,
CPDF_Dictionary* pAnnotDict);
static bool GenerateSquigglyAP(CPDF_Document* pDoc,
diff --git a/core/fpdfdoc/include/cpdf_annot.h b/core/fpdfdoc/include/cpdf_annot.h
index 914393a818..416c540cc3 100644
--- a/core/fpdfdoc/include/cpdf_annot.h
+++ b/core/fpdfdoc/include/cpdf_annot.h
@@ -61,6 +61,9 @@ class CPDF_Annot {
const CFX_Matrix* pUser2Device,
const CPDF_RenderOptions* pOptions);
CPDF_Form* GetAPForm(const CPDF_Page* pPage, AppearanceMode mode);
+ void SetOpenState(bool bOpenState) { m_bOpenState = bOpenState; }
+ CPDF_Annot* GetPopupAnnot() const { return m_pPopupAnnot; }
+ void SetPopupAnnot(CPDF_Annot* pAnnot) { m_pPopupAnnot = pAnnot; }
private:
void GenerateAPIfNeeded();
@@ -69,6 +72,11 @@ class CPDF_Annot {
CPDF_Document* const m_pDocument;
const CFX_ByteString m_sSubtype;
std::map<CPDF_Stream*, std::unique_ptr<CPDF_Form>> m_APMap;
+ // |m_bOpenState| is only set for popup annotations.
+ bool m_bOpenState;
+ // Not owned. If there is a valid pointer in |m_pPopupAnnot|,
+ // then this annot is never a popup.
+ CPDF_Annot* m_pPopupAnnot;
};
CPDF_Stream* FPDFDOC_GetAnnotAP(CPDF_Dictionary* pAnnotDict,