blob: 94e56e442f026fa2e632ededa67a4d7566bdbf9d [file] [log] [blame] [edit]
// Copyright 2016 The PDFium Authors
// 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/cpdf_defaultappearance.h"
#include <algorithm>
#include <vector>
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_simple_parser.h"
#include "core/fpdfapi/parser/fpdf_parser_utility.h"
#include "core/fpdfdoc/cpdf_formfield.h"
#include "core/fxcrt/fx_string.h"
#include "core/fxcrt/notreached.h"
#include "core/fxge/cfx_color.h"
namespace {
ByteString GetDefaultAppearanceString(const CPDF_Dictionary* annot_dict,
const CPDF_Dictionary* acroform_dict) {
ByteString default_appearance_string;
RetainPtr<const CPDF_Object> default_appearance_object =
CPDF_FormField::GetFieldAttrForDict(annot_dict, "DA");
if (default_appearance_object) {
default_appearance_string = default_appearance_object->GetString();
}
if (default_appearance_string.IsEmpty() && acroform_dict) {
default_appearance_string = acroform_dict->GetByteStringFor("DA");
}
return default_appearance_string;
}
// Find the token and its |nParams| parameters from the start of data,
// and move the current position to the start of those parameters.
bool FindTagParamFromStart(CPDF_SimpleParser* parser,
ByteStringView token,
int nParams) {
nParams++;
std::vector<uint32_t> pBuf(nParams);
int buf_index = 0;
int buf_count = 0;
parser->SetCurrentPosition(0);
while (true) {
pBuf[buf_index++] = parser->GetCurrentPosition();
if (buf_index == nParams) {
buf_index = 0;
}
buf_count++;
if (buf_count > nParams) {
buf_count = nParams;
}
ByteStringView word = parser->GetWord();
if (word.IsEmpty()) {
return false;
}
if (word == token) {
if (buf_count < nParams) {
continue;
}
parser->SetCurrentPosition(pBuf[buf_index]);
return true;
}
}
}
} // namespace
CPDF_DefaultAppearance::CPDF_DefaultAppearance(const ByteString& csDA)
: da_(csDA) {}
CPDF_DefaultAppearance::CPDF_DefaultAppearance(
const CPDF_Dictionary* annot_dict,
const CPDF_Dictionary* acroform_dict)
: CPDF_DefaultAppearance(
GetDefaultAppearanceString(annot_dict, acroform_dict)) {}
CPDF_DefaultAppearance::~CPDF_DefaultAppearance() = default;
std::optional<CPDF_DefaultAppearance::FontNameAndSize>
CPDF_DefaultAppearance::GetFont() const {
if (da_.IsEmpty()) {
return std::nullopt;
}
CPDF_SimpleParser syntax(da_.AsStringView().unsigned_span());
if (!FindTagParamFromStart(&syntax, "Tf", 2)) {
return FontNameAndSize();
}
// Deliberately using separate statements here to ensure the correct
// evaluation order.
FontNameAndSize result;
result.name = PDF_NameDecode(syntax.GetWord().Substr(1));
result.size = StringToFloat(syntax.GetWord());
return result;
}
float CPDF_DefaultAppearance::GetFontSizeOrZero() const {
auto maybe_font_name_and_size = GetFont();
if (!maybe_font_name_and_size.has_value()) {
return 0;
}
return maybe_font_name_and_size.value().size;
}
std::optional<CFX_Color> CPDF_DefaultAppearance::GetColor() const {
if (da_.IsEmpty()) {
return std::nullopt;
}
CPDF_SimpleParser syntax(da_.AsStringView().unsigned_span());
if (FindTagParamFromStart(&syntax, "g", 1)) {
float gray = StringToFloat(syntax.GetWord());
return CFX_Color(CFX_Color::Type::kGray, gray);
}
if (FindTagParamFromStart(&syntax, "rg", 3)) {
float r = StringToFloat(syntax.GetWord());
float g = StringToFloat(syntax.GetWord());
float b = StringToFloat(syntax.GetWord());
return CFX_Color(CFX_Color::Type::kRGB, r, g, b);
}
if (FindTagParamFromStart(&syntax, "k", 4)) {
float c = StringToFloat(syntax.GetWord());
float m = StringToFloat(syntax.GetWord());
float y = StringToFloat(syntax.GetWord());
float k = StringToFloat(syntax.GetWord());
return CFX_Color(CFX_Color::Type::kCMYK, c, m, y, k);
}
return std::nullopt;
}
std::optional<CFX_Color::TypeAndARGB> CPDF_DefaultAppearance::GetColorARGB()
const {
std::optional<CFX_Color> maybe_color = GetColor();
if (!maybe_color.has_value()) {
return std::nullopt;
}
const CFX_Color& color = maybe_color.value();
if (color.nColorType == CFX_Color::Type::kGray) {
int g = static_cast<int>(color.fColor1 * 255 + 0.5f);
return CFX_Color::TypeAndARGB(CFX_Color::Type::kGray,
ArgbEncode(255, g, g, g));
}
if (color.nColorType == CFX_Color::Type::kRGB) {
int r = static_cast<int>(color.fColor1 * 255 + 0.5f);
int g = static_cast<int>(color.fColor2 * 255 + 0.5f);
int b = static_cast<int>(color.fColor3 * 255 + 0.5f);
return CFX_Color::TypeAndARGB(CFX_Color::Type::kRGB,
ArgbEncode(255, r, g, b));
}
if (color.nColorType == CFX_Color::Type::kCMYK) {
float r = 1.0f - std::min(1.0f, color.fColor1 + color.fColor4);
float g = 1.0f - std::min(1.0f, color.fColor2 + color.fColor4);
float b = 1.0f - std::min(1.0f, color.fColor3 + color.fColor4);
return CFX_Color::TypeAndARGB(
CFX_Color::Type::kCMYK,
ArgbEncode(255, static_cast<int>(r * 255 + 0.5f),
static_cast<int>(g * 255 + 0.5f),
static_cast<int>(b * 255 + 0.5f)));
}
NOTREACHED();
}
// static
bool CPDF_DefaultAppearance::FindTagParamFromStartForTesting(
CPDF_SimpleParser* parser,
ByteStringView token,
int nParams) {
return FindTagParamFromStart(parser, token, nParams);
}