From af7ab33c73f58f18d0db0c90d93fa0aab0bc83f3 Mon Sep 17 00:00:00 2001 From: jaepark Date: Tue, 9 Aug 2016 10:23:14 -0700 Subject: Generate default AP stream for square annotation. This patch generates a default AP stream for square annotation so that square annotations without AP stream can be displayed. Also, roll DEPS for testing/corpus to 7f07c22 to test square annotations. BUG=62625 Review-Url: https://codereview.chromium.org/2219683002 --- core/fpdfdoc/cpdf_annot.cpp | 2 + core/fpdfdoc/cpvt_generateap.cpp | 116 ++++++++++++++++++++++++++++++++++++--- core/fpdfdoc/cpvt_generateap.h | 2 + 3 files changed, 113 insertions(+), 7 deletions(-) (limited to 'core/fpdfdoc') diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp index 726636e2a1..252e8361dd 100644 --- a/core/fpdfdoc/cpdf_annot.cpp +++ b/core/fpdfdoc/cpdf_annot.cpp @@ -23,6 +23,8 @@ CPDF_Annot::CPDF_Annot(CPDF_Dictionary* pDict, CPDF_Document* pDocument) m_sSubtype(m_pAnnotDict->GetStringBy("Subtype")) { if (m_sSubtype == "Highlight") CPVT_GenerateAP::GenerateHighlightAP(m_pDocument, m_pAnnotDict); + else if (m_sSubtype == "Square") + CPVT_GenerateAP::GenerateSquareAP(m_pDocument, m_pAnnotDict); else if (m_sSubtype == "Squiggly") CPVT_GenerateAP::GenerateSquigglyAP(m_pDocument, m_pAnnotDict); else if (m_sSubtype == "StrikeOut") diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp index f2f55b0e33..13d0fa0d38 100644 --- a/core/fpdfdoc/cpvt_generateap.cpp +++ b/core/fpdfdoc/cpvt_generateap.cpp @@ -452,10 +452,10 @@ bool GenerateWidgetAP(CPDF_Document* pDoc, return true; } -CFX_ByteString GetColorStringWithDefault(CPDF_Dictionary* pAnnotDict, +CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor, const CPVT_Color& crDefaultColor, PaintOperation nOperation) { - if (CPDF_Array* pColor = pAnnotDict->GetArrayBy("C")) { + if (pColor) { CPVT_Color color = CPVT_Color::ParseColor(*pColor); return CPVT_GenerateAP::GenerateColorAP(color, nOperation); } @@ -463,6 +463,51 @@ CFX_ByteString GetColorStringWithDefault(CPDF_Dictionary* pAnnotDict, return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation); } +FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) { + if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictBy("BS")) { + if (pBorderStyleDict->KeyExist("W")) + return pBorderStyleDict->GetNumberBy("W"); + } + + if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayBy("Border")) { + if (pBorderArray->GetCount() > 2) + return pBorderArray->GetNumberAt(2); + } + + return 1; +} + +CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) { + if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictBy("BS")) { + if (pBorderStyleDict->GetStringBy("S") == "D") + return pBorderStyleDict->GetArrayBy("D"); + } + + if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayBy("Border")) { + if (pBorderArray->GetCount() == 4) + return pBorderArray->GetArrayAt(3); + } + + return nullptr; +} + +CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) { + CPDF_Array* pDashArray = GetDashArray(pAnnotDict); + if (!pDashArray || pDashArray->IsEmpty()) + return CFX_ByteString(); + + // Support maximum of ten elements in the dash array. + size_t pDashArrayCount = std::min(pDashArray->GetCount(), 10); + CFX_ByteTextBuf sDashStream; + + sDashStream << "["; + for (size_t i = 0; i < pDashArrayCount; ++i) + sDashStream << pDashArray->GetNumberAt(i) << " "; + sDashStream << "] 0 d\n"; + + return sDashStream.MakeString(); +} + CPDF_Dictionary* GenerateExtGStateDict(const CPDF_Dictionary& pAnnotDict, const CFX_ByteString& sExtGSDictName, const CFX_ByteString& sBlendMode) { @@ -511,6 +556,12 @@ void GenerateAndSetAPDict(CPDF_Document* pDoc, pStreamDict->SetAt("Resources", pResourceDict); } +CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) { + if (bIsStrokeRect) + return bIsFillRect ? "b" : "s"; + return bIsFillRect ? "f" : "n"; +} + } // namespace bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { @@ -572,8 +623,9 @@ bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc, CFX_ByteString sExtGSDictName = "GS"; sAppStream << "/" << sExtGSDictName << " gs "; - sAppStream << GetColorStringWithDefault( - pAnnotDict, CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL); + sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), + CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), + PaintOperation::FILL); CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); rect.Normalize(); @@ -601,7 +653,7 @@ bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc, CFX_ByteString sExtGSDictName = "GS"; sAppStream << "/" << sExtGSDictName << " gs "; - sAppStream << GetColorStringWithDefault(pAnnotDict, + sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); @@ -619,6 +671,56 @@ bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc, return true; } +bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict) { + // If AP dictionary exists, we use the appearance defined in the + // existing AP dictionary. + if (pAnnotDict->KeyExist("AP")) + return false; + + CFX_ByteTextBuf sAppStream; + CFX_ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + CPDF_Array* pInteriorColor = pAnnotDict->GetArrayBy("IC"); + sAppStream << GetColorStringWithDefault(pInteriorColor, + CPVT_Color(CPVT_Color::kTransparent), + PaintOperation::FILL); + + sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), + CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), + PaintOperation::STROKE); + + FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict); + bool bIsStrokeRect = fBorderWidth > 0; + + if (bIsStrokeRect) { + sAppStream << fBorderWidth << " w "; + sAppStream << GetDashPatternString(*pAnnotDict); + } + + CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); + rect.Normalize(); + + if (bIsStrokeRect) { + // Deflating rect because stroking a path entails painting all points whose + // perpendicular distance from the path in user space is less than or equal + // to half the line width. + rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); + } + + bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0); + + sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " " + << rect.Height() << " re " + << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n"; + + CPDF_Dictionary* pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict); + return true; +} + bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { // If AP dictionary exists, we use the appearance defined in the @@ -630,7 +732,7 @@ bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc, CFX_ByteString sExtGSDictName = "GS"; sAppStream << "/" << sExtGSDictName << " gs "; - sAppStream << GetColorStringWithDefault(pAnnotDict, + sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); @@ -681,7 +783,7 @@ bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc, CFX_ByteString sExtGSDictName = "GS"; sAppStream << "/" << sExtGSDictName << " gs "; - sAppStream << GetColorStringWithDefault(pAnnotDict, + sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); diff --git a/core/fpdfdoc/cpvt_generateap.h b/core/fpdfdoc/cpvt_generateap.h index 3e4bbfe5ce..e0dd706439 100644 --- a/core/fpdfdoc/cpvt_generateap.h +++ b/core/fpdfdoc/cpvt_generateap.h @@ -31,6 +31,8 @@ class CPVT_GenerateAP { CPDF_Dictionary* pAnnotDict); static bool GenerateListBoxAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict); + static bool GenerateSquareAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict); static bool GenerateSquigglyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict); static bool GenerateStrikeOutAP(CPDF_Document* pDoc, -- cgit v1.2.3