diff options
author | Ralf Sippl <ralf.sippl@gmail.com> | 2018-03-19 23:30:28 +0000 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2018-03-19 23:30:28 +0000 |
commit | b3a5240832fce3f0b706c16070a1e69c2c1edb86 (patch) | |
tree | 36d6f6ab3853a5c241b3b437a1dc181be5329f27 /core | |
parent | 3448143cc2aa517958b6551b9419e1e6141fb5cd (diff) | |
download | pdfium-b3a5240832fce3f0b706c16070a1e69c2c1edb86.tar.xz |
Calculate AP for multi-line markup annotations correctly
Currently, when constructing AP for multi-line markup annotations, we
only take into account the first set of quadpoints, resulting in only
the first line of the annotation being displayed if the annotation spans
multiple lines.
This CL, initially written by Jane Liu <janeliulwq@google.com>
(https://pdfium-review.googlesource.com/12010) takes into account all
the quadpoints, so multi-line annotations can be displayed correctly.
BUG=pdfium:876
Change-Id: I8be10ee38e01eb6525ddef556df1b727189455c7
Reviewed-on: https://pdfium-review.googlesource.com/28590
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Diffstat (limited to 'core')
-rw-r--r-- | core/fpdfdoc/cpdf_annot.cpp | 50 | ||||
-rw-r--r-- | core/fpdfdoc/cpdf_annot.h | 8 | ||||
-rw-r--r-- | core/fpdfdoc/cpvt_generateap.cpp | 112 |
3 files changed, 113 insertions, 57 deletions
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp index cc70a3087c..91cdb12d9f 100644 --- a/core/fpdfdoc/cpdf_annot.cpp +++ b/core/fpdfdoc/cpdf_annot.cpp @@ -6,6 +6,7 @@ #include "core/fpdfdoc/cpdf_annot.h" +#include <algorithm> #include <utility> #include "core/fpdfapi/page/cpdf_form.h" @@ -158,7 +159,7 @@ CFX_FloatRect CPDF_Annot::RectForDrawing() const { bool bShouldUseQuadPointsCoords = m_bIsTextMarkupAnnotation && m_bHasGeneratedAP; if (bShouldUseQuadPointsCoords) - return RectFromQuadPoints(m_pAnnotDict.Get()); + return BoundingRectFromQuadPoints(m_pAnnotDict.Get()); return m_pAnnotDict->GetRectFor("Rect"); } @@ -205,11 +206,8 @@ CPDF_Form* CPDF_Annot::GetAPForm(const CPDF_Page* pPage, AppearanceMode mode) { } // Static. -CFX_FloatRect CPDF_Annot::RectFromQuadPoints(CPDF_Dictionary* pAnnotDict) { - CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); - if (!pArray) - return CFX_FloatRect(); - +CFX_FloatRect CPDF_Annot::RectFromQuadPointsArray(const CPDF_Array* pArray, + size_t nIndex) { // QuadPoints are defined with 4 pairs of numbers // ([ pair0, pair1, pair2, pair3 ]), where // pair0 = top_left @@ -217,11 +215,40 @@ CFX_FloatRect CPDF_Annot::RectFromQuadPoints(CPDF_Dictionary* pAnnotDict) { // pair2 = bottom_left // pair3 = bottom_right // - // On the other hand, /Rect is define as 2 pairs [pair0, pair1] where: + // On the other hand, /Rect is defined as 2 pairs [pair0, pair1] where: // pair0 = bottom_left // pair1 = top_right. - return CFX_FloatRect(pArray->GetNumberAt(4), pArray->GetNumberAt(5), - pArray->GetNumberAt(2), pArray->GetNumberAt(3)); + + return CFX_FloatRect( + pArray->GetNumberAt(4 + nIndex * 8), pArray->GetNumberAt(5 + nIndex * 8), + pArray->GetNumberAt(2 + nIndex * 8), pArray->GetNumberAt(3 + nIndex * 8)); +} + +// Static. +CFX_FloatRect CPDF_Annot::BoundingRectFromQuadPoints( + CPDF_Dictionary* pAnnotDict) { + CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (!pArray) + return CFX_FloatRect(); + + CFX_FloatRect ret = RectFromQuadPointsArray(pArray, 0); + size_t nQuadPointCount = QuadPointCount(pArray); + for (size_t i = 1; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = RectFromQuadPointsArray(pArray, i); + ret.Union(rect); + } + return ret; +} + +// Static. +CFX_FloatRect CPDF_Annot::RectFromQuadPoints(CPDF_Dictionary* pAnnotDict, + size_t nIndex) { + CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); + + if (!pArray) + return CFX_FloatRect(); + + return RectFromQuadPointsArray(pArray, nIndex); } // Static. @@ -348,6 +375,11 @@ ByteString CPDF_Annot::AnnotSubtypeToString(CPDF_Annot::Subtype nSubtype) { return ""; } +// Static. +size_t CPDF_Annot::QuadPointCount(const CPDF_Array* pArray) { + return pArray->GetCount() / 8; +} + bool CPDF_Annot::DrawAppearance(CPDF_Page* pPage, CFX_RenderDevice* pDevice, const CFX_Matrix& mtUser2Device, diff --git a/core/fpdfdoc/cpdf_annot.h b/core/fpdfdoc/cpdf_annot.h index 499c62dcba..3f1164ad18 100644 --- a/core/fpdfdoc/cpdf_annot.h +++ b/core/fpdfdoc/cpdf_annot.h @@ -16,6 +16,7 @@ #include "core/fxcrt/maybe_owned.h" class CFX_RenderDevice; +class CPDF_Array; class CPDF_Dictionary; class CPDF_Document; class CPDF_Form; @@ -66,7 +67,12 @@ class CPDF_Annot { static bool IsAnnotationHidden(CPDF_Dictionary* pAnnotDict); static CPDF_Annot::Subtype StringToAnnotSubtype(const ByteString& sSubtype); static ByteString AnnotSubtypeToString(CPDF_Annot::Subtype nSubtype); - static CFX_FloatRect RectFromQuadPoints(CPDF_Dictionary* pAnnotDict); + static CFX_FloatRect RectFromQuadPointsArray(const CPDF_Array* pArray, + size_t nIndex); + static CFX_FloatRect BoundingRectFromQuadPoints(CPDF_Dictionary* pAnnotDict); + static CFX_FloatRect RectFromQuadPoints(CPDF_Dictionary* pAnnotDict, + size_t nIndex); + static size_t QuadPointCount(const CPDF_Array* pArray); // The second constructor does not take ownership of the dictionary. CPDF_Annot(std::unique_ptr<CPDF_Dictionary> pDict, CPDF_Document* pDocument); diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp index eb3e22d870..e2fbcc9720 100644 --- a/core/fpdfdoc/cpvt_generateap.cpp +++ b/core/fpdfdoc/cpvt_generateap.cpp @@ -519,7 +519,7 @@ void GenerateAndSetAPDict(CPDF_Document* pDoc, pStreamDict->SetMatrixFor("Matrix", CFX_Matrix()); CFX_FloatRect rect = bIsTextMarkupAnnotation - ? CPDF_Annot::RectFromQuadPoints(pAnnotDict) + ? CPDF_Annot::BoundingRectFromQuadPoints(pAnnotDict) : pAnnotDict->GetRectFor("Rect"); pStreamDict->SetRectFor("BBox", rect); pStreamDict->SetFor("Resources", std::move(pResourceDict)); @@ -606,13 +606,18 @@ bool GenerateHighlightAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { CFX_Color(CFX_Color::kRGB, 1, 1, 0), PaintOperation::FILL); - CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); - rect.Normalize(); + CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); - sAppStream << rect.left << " " << rect.top << " m " << rect.right << " " - << rect.top << " l " << rect.right << " " << rect.bottom << " l " - << rect.left << " " << rect.bottom << " l " - << "h f\n"; + sAppStream << rect.left << " " << rect.top << " m " << rect.right << " " + << rect.top << " l " << rect.right << " " << rect.bottom + << " l " << rect.left << " " << rect.bottom << " l h f\n"; + } + } auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply"); @@ -708,13 +713,18 @@ bool GenerateUnderlineAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { CFX_Color(CFX_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); - CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); - rect.Normalize(); - - float fLineWidth = 1.0; - sAppStream << fLineWidth << " w " << rect.left << " " - << rect.bottom + fLineWidth << " m " << rect.right << " " - << rect.bottom + fLineWidth << " l S\n"; + CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + static constexpr float kLineWidth = 1.0f; + sAppStream << kLineWidth << " w "; + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + sAppStream << rect.left << " " << rect.bottom + kLineWidth << " m " + << rect.right << " " << rect.bottom + kLineWidth << " l S\n"; + } + } auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); @@ -817,36 +827,38 @@ bool GenerateSquigglyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { CFX_Color(CFX_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); - CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); - rect.Normalize(); - - float fLineWidth = 1.0; - sAppStream << fLineWidth << " w "; - - const float fDelta = 2.0; - const float fTop = rect.bottom + fDelta; - const float fBottom = rect.bottom; - - sAppStream << rect.left << " " << fTop << " m "; - - float fX = rect.left + fDelta; - bool isUpwards = false; + CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + static constexpr float kLineWidth = 1.0f; + static constexpr float kDelta = 2.0f; + sAppStream << kLineWidth << " w "; + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + + const float fTop = rect.bottom + kDelta; + const float fBottom = rect.bottom; + sAppStream << rect.left << " " << fTop << " m "; + + float fX = rect.left + kDelta; + bool isUpwards = false; + while (fX < rect.right) { + sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l "; + fX += kDelta; + isUpwards = !isUpwards; + } - while (fX < rect.right) { - sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l "; + float fRemainder = rect.right - (fX - kDelta); + if (isUpwards) + sAppStream << rect.right << " " << fBottom + fRemainder << " l "; + else + sAppStream << rect.right << " " << fTop - fRemainder << " l "; - fX += fDelta; - isUpwards = !isUpwards; + sAppStream << "S\n"; + } } - float fRemainder = rect.right - (fX - fDelta); - if (isUpwards) - sAppStream << rect.right << " " << fBottom + fRemainder << " l "; - else - sAppStream << rect.right << " " << fTop - fRemainder << " l "; - - sAppStream << "S\n"; - auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); auto pResourceDict = @@ -865,13 +877,19 @@ bool GenerateStrikeOutAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { CFX_Color(CFX_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); - CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); - rect.Normalize(); - - float fLineWidth = 1.0; - float fY = (rect.top + rect.bottom) / 2; - sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m " - << rect.right << " " << fY << " l S\n"; + CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + static constexpr float kLineWidth = 1.0f; + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + + float fY = (rect.top + rect.bottom) / 2; + sAppStream << kLineWidth << " w " << rect.left << " " << fY << " m " + << rect.right << " " << fY << " l S\n"; + } + } auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); |