// 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. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fpdfapi/page/cpdf_clippath.h" #include #include "core/fpdfapi/page/cpdf_textobject.h" CPDF_ClipPath::CPDF_ClipPath() = default; CPDF_ClipPath::CPDF_ClipPath(const CPDF_ClipPath& that) = default; CPDF_ClipPath& CPDF_ClipPath::operator=(const CPDF_ClipPath& that) = default; CPDF_ClipPath::~CPDF_ClipPath() = default; size_t CPDF_ClipPath::GetPathCount() const { return m_Ref.GetObject()->m_PathAndTypeList.size(); } CPDF_Path CPDF_ClipPath::GetPath(size_t i) const { return m_Ref.GetObject()->m_PathAndTypeList[i].first; } uint8_t CPDF_ClipPath::GetClipType(size_t i) const { return m_Ref.GetObject()->m_PathAndTypeList[i].second; } size_t CPDF_ClipPath::GetTextCount() const { return m_Ref.GetObject()->m_TextList.size(); } CPDF_TextObject* CPDF_ClipPath::GetText(size_t i) const { return m_Ref.GetObject()->m_TextList[i].get(); } CFX_FloatRect CPDF_ClipPath::GetClipBox() const { CFX_FloatRect rect; bool bStarted = false; if (GetPathCount() > 0) { rect = GetPath(0).GetBoundingBox(); for (size_t i = 1; i < GetPathCount(); ++i) { CFX_FloatRect path_rect = GetPath(i).GetBoundingBox(); rect.Intersect(path_rect); } bStarted = true; } CFX_FloatRect layer_rect; bool bLayerStarted = false; for (size_t i = 0; i < GetTextCount(); ++i) { CPDF_TextObject* pTextObj = GetText(i); if (pTextObj) { if (bLayerStarted) { layer_rect.Union(CFX_FloatRect(pTextObj->GetBBox())); } else { layer_rect = CFX_FloatRect(pTextObj->GetBBox()); bLayerStarted = true; } } else { if (bStarted) { rect.Intersect(layer_rect); } else { rect = layer_rect; bStarted = true; } bLayerStarted = false; } } return rect; } void CPDF_ClipPath::AppendPath(CPDF_Path path, uint8_t type, bool bAutoMerge) { PathData* pData = m_Ref.GetPrivateCopy(); if (!pData->m_PathAndTypeList.empty() && bAutoMerge) { const CPDF_Path& old_path = pData->m_PathAndTypeList.back().first; if (old_path.IsRect()) { CFX_PointF point0 = old_path.GetPoint(0); CFX_PointF point2 = old_path.GetPoint(2); CFX_FloatRect old_rect(point0.x, point0.y, point2.x, point2.y); CFX_FloatRect new_rect = path.GetBoundingBox(); if (old_rect.Contains(new_rect)) pData->m_PathAndTypeList.pop_back(); } } pData->m_PathAndTypeList.push_back(std::make_pair(path, type)); } void CPDF_ClipPath::AppendTexts( std::vector>* pTexts) { constexpr size_t kMaxTextObjects = 1024; PathData* pData = m_Ref.GetPrivateCopy(); if (pData->m_TextList.size() + pTexts->size() <= kMaxTextObjects) { for (size_t i = 0; i < pTexts->size(); i++) pData->m_TextList.push_back(std::move((*pTexts)[i])); pData->m_TextList.push_back(nullptr); } pTexts->clear(); } void CPDF_ClipPath::CopyClipPath(const CPDF_ClipPath& that) { if (*this == that || !that.HasRef()) return; for (size_t i = 0; i < that.GetPathCount(); ++i) AppendPath(that.GetPath(i), that.GetClipType(i), /*bAutoMerge=*/false); } void CPDF_ClipPath::Transform(const CFX_Matrix& matrix) { PathData* pData = m_Ref.GetPrivateCopy(); for (auto& obj : pData->m_PathAndTypeList) obj.first.Transform(matrix); for (auto& text : pData->m_TextList) { if (text) text->Transform(matrix); } } CPDF_ClipPath::PathData::PathData() = default; CPDF_ClipPath::PathData::PathData(const PathData& that) { m_PathAndTypeList = that.m_PathAndTypeList; m_TextList.resize(that.m_TextList.size()); for (size_t i = 0; i < that.m_TextList.size(); ++i) { if (that.m_TextList[i]) m_TextList[i] = that.m_TextList[i]->Clone(); } } CPDF_ClipPath::PathData::~PathData() = default; RetainPtr CPDF_ClipPath::PathData::Clone() const { return pdfium::MakeRetain(*this); }