mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 13:57:35 +00:00
LibPDF: Replace Value class by AK::Variant
This decreases the memory consumption by LibPDF by 4 bytes per Value, compensating exactly for the increase in an earlier commit. :^)
This commit is contained in:
parent
d344253b08
commit
f84a7e2e22
7 changed files with 132 additions and 243 deletions
|
@ -60,10 +60,10 @@ RefPtr<CalRGBColorSpace> CalRGBColorSpace::create(RefPtr<Document> document, Vec
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto param = parameters[0];
|
auto param = parameters[0];
|
||||||
if (!param.is_object() || !param.as_object()->is_dict())
|
if (!param.has<NonnullRefPtr<Object>>() || !param.get<NonnullRefPtr<Object>>()->is_dict())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto dict = object_cast<DictObject>(param.as_object());
|
auto dict = object_cast<DictObject>(param.get<NonnullRefPtr<Object>>());
|
||||||
if (!dict->contains(CommonNames::WhitePoint))
|
if (!dict->contains(CommonNames::WhitePoint))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ Document::Document(NonnullRefPtr<Parser> const& parser)
|
||||||
Value Document::get_or_load_value(u32 index)
|
Value Document::get_or_load_value(u32 index)
|
||||||
{
|
{
|
||||||
auto value = get_value(index);
|
auto value = get_value(index);
|
||||||
if (value)
|
if (!value.has<Empty>()) // FIXME: Use Optional instead?
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
auto object = m_parser->parse_object_with_index(index);
|
auto object = m_parser->parse_object_with_index(index);
|
||||||
|
@ -122,7 +122,7 @@ Page Document::get_page(u32 index)
|
||||||
|
|
||||||
int rotate = 0;
|
int rotate = 0;
|
||||||
if (raw_page_object->contains(CommonNames::Rotate)) {
|
if (raw_page_object->contains(CommonNames::Rotate)) {
|
||||||
rotate = raw_page_object->get_value(CommonNames::Rotate).as_int();
|
rotate = raw_page_object->get_value(CommonNames::Rotate).get<int>();
|
||||||
VERIFY(rotate % 90 == 0);
|
VERIFY(rotate % 90 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,22 +133,22 @@ Page Document::get_page(u32 index)
|
||||||
|
|
||||||
Value Document::resolve(Value const& value)
|
Value Document::resolve(Value const& value)
|
||||||
{
|
{
|
||||||
if (value.is_ref()) {
|
if (value.has<Reference>()) {
|
||||||
// FIXME: Surely indirect PDF objects can't contain another indirect PDF object,
|
// FIXME: Surely indirect PDF objects can't contain another indirect PDF object,
|
||||||
// right? Unsure from the spec, but if they can, these return values would have
|
// right? Unsure from the spec, but if they can, these return values would have
|
||||||
// to be wrapped with another resolve() call.
|
// to be wrapped with another resolve() call.
|
||||||
return get_or_load_value(value.as_ref_index());
|
return get_or_load_value(value.as_ref_index());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value.is_object())
|
if (!value.has<NonnullRefPtr<Object>>())
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
auto obj = value.as_object();
|
auto& obj = value.get<NonnullRefPtr<Object>>();
|
||||||
|
|
||||||
if (obj->is_indirect_value())
|
if (obj->is_indirect_value())
|
||||||
return static_ptr_cast<IndirectValue>(obj)->value();
|
return static_ptr_cast<IndirectValue>(obj)->value();
|
||||||
|
|
||||||
return obj;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Document::build_page_tree()
|
bool Document::build_page_tree()
|
||||||
|
@ -165,7 +165,7 @@ bool Document::add_page_tree_node_to_page_tree(NonnullRefPtr<DictObject> const&
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto kids_array = page_tree->get_array(this, CommonNames::Kids);
|
auto kids_array = page_tree->get_array(this, CommonNames::Kids);
|
||||||
auto page_count = page_tree->get(CommonNames::Count).value().as_int();
|
auto page_count = page_tree->get(CommonNames::Count).value().get<int>();
|
||||||
|
|
||||||
if (static_cast<size_t>(page_count) != kids_array->elements().size()) {
|
if (static_cast<size_t>(page_count) != kids_array->elements().size()) {
|
||||||
// This page tree contains child page trees, so we recursively add
|
// This page tree contains child page trees, so we recursively add
|
||||||
|
@ -213,7 +213,7 @@ void Document::build_outline()
|
||||||
m_outline->children = move(children);
|
m_outline->children = move(children);
|
||||||
|
|
||||||
if (outline_dict->contains(CommonNames::Count))
|
if (outline_dict->contains(CommonNames::Count))
|
||||||
m_outline->count = outline_dict->get_value(CommonNames::Count).as_int();
|
m_outline->count = outline_dict->get_value(CommonNames::Count).get<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<OutlineItem> Document::build_outline_item(NonnullRefPtr<DictObject> const& outline_item_dict)
|
NonnullRefPtr<OutlineItem> Document::build_outline_item(NonnullRefPtr<DictObject> const& outline_item_dict)
|
||||||
|
@ -232,7 +232,7 @@ NonnullRefPtr<OutlineItem> Document::build_outline_item(NonnullRefPtr<DictObject
|
||||||
outline_item->title = outline_item_dict->get_string(this, CommonNames::Title)->string();
|
outline_item->title = outline_item_dict->get_string(this, CommonNames::Title)->string();
|
||||||
|
|
||||||
if (outline_item_dict->contains(CommonNames::Count))
|
if (outline_item_dict->contains(CommonNames::Count))
|
||||||
outline_item->count = outline_item_dict->get_value(CommonNames::Count).as_int();
|
outline_item->count = outline_item_dict->get_value(CommonNames::Count).get<int>();
|
||||||
|
|
||||||
if (outline_item_dict->contains(CommonNames::Dest)) {
|
if (outline_item_dict->contains(CommonNames::Dest)) {
|
||||||
auto dest_arr = outline_item_dict->get_array(this, CommonNames::Dest);
|
auto dest_arr = outline_item_dict->get_array(this, CommonNames::Dest);
|
||||||
|
@ -269,14 +269,14 @@ NonnullRefPtr<OutlineItem> Document::build_outline_item(NonnullRefPtr<DictObject
|
||||||
|
|
||||||
if (outline_item_dict->contains(CommonNames::C)) {
|
if (outline_item_dict->contains(CommonNames::C)) {
|
||||||
auto color_array = outline_item_dict->get_array(this, CommonNames::C);
|
auto color_array = outline_item_dict->get_array(this, CommonNames::C);
|
||||||
auto r = static_cast<int>(255.0f * color_array->at(0).as_float());
|
auto r = static_cast<int>(255.0f * color_array->at(0).get<float>());
|
||||||
auto g = static_cast<int>(255.0f * color_array->at(1).as_float());
|
auto g = static_cast<int>(255.0f * color_array->at(1).get<float>());
|
||||||
auto b = static_cast<int>(255.0f * color_array->at(2).as_float());
|
auto b = static_cast<int>(255.0f * color_array->at(2).get<float>());
|
||||||
outline_item->color = Color(r, g, b);
|
outline_item->color = Color(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outline_item_dict->contains(CommonNames::F)) {
|
if (outline_item_dict->contains(CommonNames::F)) {
|
||||||
auto bitfield = outline_item_dict->get_value(CommonNames::F).as_int();
|
auto bitfield = outline_item_dict->get_value(CommonNames::F).get<int>();
|
||||||
outline_item->italic = bitfield & 0x1;
|
outline_item->italic = bitfield & 0x1;
|
||||||
outline_item->bold = bitfield & 0x2;
|
outline_item->bold = bitfield & 0x2;
|
||||||
}
|
}
|
||||||
|
@ -286,12 +286,13 @@ NonnullRefPtr<OutlineItem> Document::build_outline_item(NonnullRefPtr<DictObject
|
||||||
|
|
||||||
NonnullRefPtrVector<OutlineItem> Document::build_outline_item_chain(Value const& first_ref, Value const& last_ref)
|
NonnullRefPtrVector<OutlineItem> Document::build_outline_item_chain(Value const& first_ref, Value const& last_ref)
|
||||||
{
|
{
|
||||||
VERIFY(first_ref.is_ref());
|
VERIFY(first_ref.has<Reference>());
|
||||||
VERIFY(last_ref.is_ref());
|
VERIFY(last_ref.has<Reference>());
|
||||||
|
|
||||||
NonnullRefPtrVector<OutlineItem> children;
|
NonnullRefPtrVector<OutlineItem> children;
|
||||||
|
|
||||||
auto first_dict = object_cast<DictObject>(get_or_load_value(first_ref.as_ref_index()).as_object());
|
auto first_dict = object_cast<DictObject>(
|
||||||
|
get_or_load_value(first_ref.as_ref_index()).get<NonnullRefPtr<Object>>());
|
||||||
auto first = build_outline_item(first_dict);
|
auto first = build_outline_item(first_dict);
|
||||||
children.append(first);
|
children.append(first);
|
||||||
|
|
||||||
|
@ -301,7 +302,7 @@ NonnullRefPtrVector<OutlineItem> Document::build_outline_item_chain(Value const&
|
||||||
while (current_child_dict->contains(CommonNames::Next)) {
|
while (current_child_dict->contains(CommonNames::Next)) {
|
||||||
auto next_child_dict_ref = current_child_dict->get_value(CommonNames::Next);
|
auto next_child_dict_ref = current_child_dict->get_value(CommonNames::Next);
|
||||||
current_child_index = next_child_dict_ref.as_ref_index();
|
current_child_index = next_child_dict_ref.as_ref_index();
|
||||||
auto next_child_dict = object_cast<DictObject>(get_or_load_value(current_child_index).as_object());
|
auto next_child_dict = object_cast<DictObject>(get_or_load_value(current_child_index).get<NonnullRefPtr<Object>>());
|
||||||
auto next_child = build_outline_item(next_child_dict);
|
auto next_child = build_outline_item(next_child_dict);
|
||||||
children.append(next_child);
|
children.append(next_child);
|
||||||
|
|
||||||
|
|
|
@ -102,13 +102,13 @@ public:
|
||||||
auto resolved = resolve(value);
|
auto resolved = resolve(value);
|
||||||
|
|
||||||
if constexpr (IsSame<T, bool>)
|
if constexpr (IsSame<T, bool>)
|
||||||
return resolved.as_bool();
|
return resolved.get<bool>();
|
||||||
if constexpr (IsSame<T, int>)
|
if constexpr (IsSame<T, int>)
|
||||||
return resolved.as_int();
|
return resolved.get<int>();
|
||||||
if constexpr (IsSame<T, float>)
|
if constexpr (IsSame<T, float>)
|
||||||
return resolved.as_float();
|
return resolved.get<float>();
|
||||||
if constexpr (IsObject<T>)
|
if constexpr (IsObject<T>)
|
||||||
return object_cast<T>(resolved.as_object());
|
return object_cast<T>(resolved.get<NonnullRefPtr<Object>>());
|
||||||
|
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,10 +125,10 @@ Parser::LinearizationResult Parser::initialize_linearization_dict()
|
||||||
{
|
{
|
||||||
// parse_header() is called immediately before this, so we are at the right location
|
// parse_header() is called immediately before this, so we are at the right location
|
||||||
auto dict_value = m_document->resolve(parse_indirect_value());
|
auto dict_value = m_document->resolve(parse_indirect_value());
|
||||||
if (!dict_value || !dict_value.is_object())
|
if (!dict_value.has<NonnullRefPtr<Object>>())
|
||||||
return LinearizationResult::Error;
|
return LinearizationResult::Error;
|
||||||
|
|
||||||
auto dict_object = dict_value.as_object();
|
auto dict_object = dict_value.get<NonnullRefPtr<Object>>();
|
||||||
if (!dict_object->is_dict())
|
if (!dict_object->is_dict())
|
||||||
return LinearizationResult::NotLinearized;
|
return LinearizationResult::NotLinearized;
|
||||||
|
|
||||||
|
@ -149,16 +149,16 @@ Parser::LinearizationResult Parser::initialize_linearization_dict()
|
||||||
auto first_page = dict->get(CommonNames::P).value_or({});
|
auto first_page = dict->get(CommonNames::P).value_or({});
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
if (!length_of_file.is_int_type<u32>()
|
if (!length_of_file.has_u32()
|
||||||
|| !hint_table.is_object()
|
|| !hint_table.has<NonnullRefPtr<Object>>()
|
||||||
|| !first_page_object_number.is_int_type<u32>()
|
|| !first_page_object_number.has_u32()
|
||||||
|| !number_of_pages.is_int_type<u16>()
|
|| !number_of_pages.has_u16()
|
||||||
|| !offset_of_main_xref_table.is_int_type<u32>()
|
|| !offset_of_main_xref_table.has_u32()
|
||||||
|| (first_page && !first_page.is_int_type<u32>())) {
|
|| (!first_page.has<Empty>() && !first_page.has_u32())) {
|
||||||
return LinearizationResult::Error;
|
return LinearizationResult::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hint_table_object = hint_table.as_object();
|
auto hint_table_object = hint_table.get<NonnullRefPtr<Object>>();
|
||||||
if (!hint_table_object->is_array())
|
if (!hint_table_object->is_array())
|
||||||
return LinearizationResult::Error;
|
return LinearizationResult::Error;
|
||||||
|
|
||||||
|
@ -177,24 +177,24 @@ Parser::LinearizationResult Parser::initialize_linearization_dict()
|
||||||
overflow_hint_stream_length = hint_table_array->at(3);
|
overflow_hint_stream_length = hint_table_array->at(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!primary_hint_stream_offset.is_int_type<u32>()
|
if (!primary_hint_stream_offset.has_u32()
|
||||||
|| !primary_hint_stream_length.is_int_type<u32>()
|
|| !primary_hint_stream_length.has_u32()
|
||||||
|| (overflow_hint_stream_offset && !overflow_hint_stream_offset.is_int_type<u32>())
|
|| (!overflow_hint_stream_offset.has<Empty>() && !overflow_hint_stream_offset.has_u32())
|
||||||
|| (overflow_hint_stream_length && !overflow_hint_stream_length.is_int_type<u32>())) {
|
|| (!overflow_hint_stream_length.has<Empty>() && !overflow_hint_stream_length.has_u32())) {
|
||||||
return LinearizationResult::Error;
|
return LinearizationResult::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_linearization_dictionary = LinearizationDictionary {
|
m_linearization_dictionary = LinearizationDictionary {
|
||||||
length_of_file.as_int_type<u32>(),
|
length_of_file.get_u32(),
|
||||||
primary_hint_stream_offset.as_int_type<u32>(),
|
primary_hint_stream_offset.get_u32(),
|
||||||
primary_hint_stream_length.as_int_type<u32>(),
|
primary_hint_stream_length.get_u32(),
|
||||||
overflow_hint_stream_offset ? overflow_hint_stream_offset.as_int_type<u32>() : NumericLimits<u32>::max(),
|
overflow_hint_stream_offset.has<Empty>() ? NumericLimits<u32>::max() : overflow_hint_stream_offset.get_u32(),
|
||||||
overflow_hint_stream_length ? overflow_hint_stream_length.as_int_type<u32>() : NumericLimits<u32>::max(),
|
overflow_hint_stream_length.has<Empty>() ? NumericLimits<u32>::max() : overflow_hint_stream_length.get_u32(),
|
||||||
first_page_object_number.as_int_type<u32>(),
|
first_page_object_number.get_u32(),
|
||||||
offset_of_first_page_end.as_int_type<u32>(),
|
offset_of_first_page_end.get_u32(),
|
||||||
number_of_pages.as_int_type<u16>(),
|
number_of_pages.get_u16(),
|
||||||
offset_of_main_xref_table.as_int_type<u32>(),
|
offset_of_main_xref_table.get_u32(),
|
||||||
first_page ? first_page.as_int_type<u32>() : NumericLimits<u32>::max(),
|
first_page.has<Empty>() ? NumericLimits<u32>::max() : first_page.get_u32(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return LinearizationResult::Linearized;
|
return LinearizationResult::Linearized;
|
||||||
|
@ -241,10 +241,10 @@ bool Parser::initialize_hint_tables()
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto stream_value = stream_indirect_value->value();
|
auto stream_value = stream_indirect_value->value();
|
||||||
if (!stream_value.is_object())
|
if (!stream_value.has<NonnullRefPtr<Object>>())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto stream_object = stream_value.as_object();
|
auto stream_object = stream_value.get<NonnullRefPtr<Object>>();
|
||||||
if (!stream_object->is_stream())
|
if (!stream_object->is_stream())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -310,9 +310,9 @@ bool Parser::initialize_non_linearized_xref_table()
|
||||||
|
|
||||||
m_reader.set_reading_forwards();
|
m_reader.set_reading_forwards();
|
||||||
auto xref_offset_value = parse_number();
|
auto xref_offset_value = parse_number();
|
||||||
if (!xref_offset_value.is_int())
|
if (!xref_offset_value.has<int>())
|
||||||
return false;
|
return false;
|
||||||
auto xref_offset = xref_offset_value.as_int();
|
auto xref_offset = xref_offset_value.get<int>();
|
||||||
|
|
||||||
m_reader.move_to(xref_offset);
|
m_reader.move_to(xref_offset);
|
||||||
m_xref_table = parse_xref_table();
|
m_xref_table = parse_xref_table();
|
||||||
|
@ -339,9 +339,9 @@ RefPtr<XRefTable> Parser::parse_xref_table()
|
||||||
Vector<XRefEntry> entries;
|
Vector<XRefEntry> entries;
|
||||||
|
|
||||||
auto starting_index_value = parse_number();
|
auto starting_index_value = parse_number();
|
||||||
auto starting_index = starting_index_value.as_int();
|
auto starting_index = starting_index_value.get<int>();
|
||||||
auto object_count_value = parse_number();
|
auto object_count_value = parse_number();
|
||||||
auto object_count = object_count_value.as_int();
|
auto object_count = object_count_value.get<int>();
|
||||||
|
|
||||||
for (int i = 0; i < object_count; i++) {
|
for (int i = 0; i < object_count; i++) {
|
||||||
auto offset_string = String(m_reader.bytes().slice(m_reader.offset(), 10));
|
auto offset_string = String(m_reader.bytes().slice(m_reader.offset(), 10));
|
||||||
|
@ -603,7 +603,7 @@ Value Parser::parse_value()
|
||||||
if (m_reader.matches("null")) {
|
if (m_reader.matches("null")) {
|
||||||
m_reader.move_by(4);
|
m_reader.move_by(4);
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
return Value(Value::NullTag {});
|
return Value(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_reader.matches("true")) {
|
if (m_reader.matches("true")) {
|
||||||
|
@ -646,12 +646,12 @@ Value Parser::parse_value()
|
||||||
Value Parser::parse_possible_indirect_value_or_ref()
|
Value Parser::parse_possible_indirect_value_or_ref()
|
||||||
{
|
{
|
||||||
auto first_number = parse_number();
|
auto first_number = parse_number();
|
||||||
if (!first_number.is_int() || !matches_number())
|
if (!first_number.has<int>() || !matches_number())
|
||||||
return first_number;
|
return first_number;
|
||||||
|
|
||||||
m_reader.save();
|
m_reader.save();
|
||||||
auto second_number = parse_number();
|
auto second_number = parse_number();
|
||||||
if (!second_number.is_int()) {
|
if (!second_number.has<int>()) {
|
||||||
m_reader.load();
|
m_reader.load();
|
||||||
return first_number;
|
return first_number;
|
||||||
}
|
}
|
||||||
|
@ -660,12 +660,12 @@ Value Parser::parse_possible_indirect_value_or_ref()
|
||||||
m_reader.discard();
|
m_reader.discard();
|
||||||
consume();
|
consume();
|
||||||
consume_whitespace();
|
consume_whitespace();
|
||||||
return Value(Reference(first_number.as_int(), second_number.as_int()));
|
return Value(Reference(first_number.get<int>(), second_number.get<int>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_reader.matches("obj")) {
|
if (m_reader.matches("obj")) {
|
||||||
m_reader.discard();
|
m_reader.discard();
|
||||||
return parse_indirect_value(first_number.as_int(), second_number.as_int());
|
return parse_indirect_value(first_number.get<int>(), second_number.get<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_reader.load();
|
m_reader.load();
|
||||||
|
@ -692,12 +692,12 @@ RefPtr<IndirectValue> Parser::parse_indirect_value(int index, int generation)
|
||||||
RefPtr<IndirectValue> Parser::parse_indirect_value()
|
RefPtr<IndirectValue> Parser::parse_indirect_value()
|
||||||
{
|
{
|
||||||
auto first_number = parse_number();
|
auto first_number = parse_number();
|
||||||
if (!first_number.is_int())
|
if (!first_number.has<int>())
|
||||||
return {};
|
return {};
|
||||||
auto second_number = parse_number();
|
auto second_number = parse_number();
|
||||||
if (!second_number.is_int())
|
if (!second_number.has<int>())
|
||||||
return {};
|
return {};
|
||||||
return parse_indirect_value(first_number.as_int(), second_number.as_int());
|
return parse_indirect_value(first_number.get<int>(), second_number.get<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Parser::parse_number()
|
Value Parser::parse_number()
|
||||||
|
@ -928,7 +928,7 @@ RefPtr<ArrayObject> Parser::parse_array()
|
||||||
|
|
||||||
while (!m_reader.matches(']')) {
|
while (!m_reader.matches(']')) {
|
||||||
auto value = parse_value();
|
auto value = parse_value();
|
||||||
if (!value)
|
if (value.has<Empty>())
|
||||||
return {};
|
return {};
|
||||||
values.append(value);
|
values.append(value);
|
||||||
}
|
}
|
||||||
|
@ -954,7 +954,7 @@ RefPtr<DictObject> Parser::parse_dict()
|
||||||
if (!name)
|
if (!name)
|
||||||
return {};
|
return {};
|
||||||
auto value = parse_value();
|
auto value = parse_value();
|
||||||
if (!value)
|
if (value.has<Empty>())
|
||||||
return {};
|
return {};
|
||||||
map.set(name->name(), value);
|
map.set(name->name(), value);
|
||||||
}
|
}
|
||||||
|
@ -1004,14 +1004,14 @@ RefPtr<DictObject> Parser::conditionally_parse_page_tree_node(u32 object_index,
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto value = parse_value();
|
auto value = parse_value();
|
||||||
if (!value) {
|
if (value.has<Empty>()) {
|
||||||
ok = false;
|
ok = false;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (name_string == CommonNames::Type) {
|
if (name_string == CommonNames::Type) {
|
||||||
if (!value.is_object())
|
if (!value.has<NonnullRefPtr<Object>>())
|
||||||
return {};
|
return {};
|
||||||
auto type_object = value.as_object();
|
auto type_object = value.get<NonnullRefPtr<Object>>();
|
||||||
if (!type_object->is_name())
|
if (!type_object->is_name())
|
||||||
return {};
|
return {};
|
||||||
auto type_name = object_cast<NameObject>(type_object);
|
auto type_name = object_cast<NameObject>(type_object);
|
||||||
|
@ -1039,7 +1039,7 @@ RefPtr<StreamObject> Parser::parse_stream(NonnullRefPtr<DictObject> dict)
|
||||||
ReadonlyBytes bytes;
|
ReadonlyBytes bytes;
|
||||||
|
|
||||||
auto maybe_length = dict->get(CommonNames::Length);
|
auto maybe_length = dict->get(CommonNames::Length);
|
||||||
if (maybe_length.has_value() && (!maybe_length->is_ref() || m_xref_table)) {
|
if (maybe_length.has_value() && (!maybe_length->has<Reference>() || m_xref_table)) {
|
||||||
// The PDF writer has kindly provided us with the direct length of the stream
|
// The PDF writer has kindly provided us with the direct length of the stream
|
||||||
m_reader.save();
|
m_reader.save();
|
||||||
auto length = m_document->resolve_to<int>(maybe_length.value());
|
auto length = m_document->resolve_to<int>(maybe_length.value());
|
||||||
|
|
|
@ -132,12 +132,12 @@ RENDERER_HANDLER(set_line_width)
|
||||||
|
|
||||||
RENDERER_HANDLER(set_line_cap)
|
RENDERER_HANDLER(set_line_cap)
|
||||||
{
|
{
|
||||||
state().line_cap_style = static_cast<LineCapStyle>(args[0].as_int());
|
state().line_cap_style = static_cast<LineCapStyle>(args[0].get<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
RENDERER_HANDLER(set_line_join)
|
RENDERER_HANDLER(set_line_join)
|
||||||
{
|
{
|
||||||
state().line_join_style = static_cast<LineJoinStyle>(args[0].as_int());
|
state().line_join_style = static_cast<LineJoinStyle>(args[0].get<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
RENDERER_HANDLER(set_miter_limit)
|
RENDERER_HANDLER(set_miter_limit)
|
||||||
|
@ -150,8 +150,8 @@ RENDERER_HANDLER(set_dash_pattern)
|
||||||
auto dash_array = m_document->resolve_to<ArrayObject>(args[0]);
|
auto dash_array = m_document->resolve_to<ArrayObject>(args[0]);
|
||||||
Vector<int> pattern;
|
Vector<int> pattern;
|
||||||
for (auto& element : *dash_array)
|
for (auto& element : *dash_array)
|
||||||
pattern.append(element.as_int());
|
pattern.append(element.get<int>());
|
||||||
state().line_dash_pattern = LineDashPattern { pattern, args[1].as_int() };
|
state().line_dash_pattern = LineDashPattern { pattern, args[1].get<int>() };
|
||||||
}
|
}
|
||||||
|
|
||||||
RENDERER_TODO(set_color_rendering_intent);
|
RENDERER_TODO(set_color_rendering_intent);
|
||||||
|
@ -335,7 +335,7 @@ RENDERER_HANDLER(text_set_font)
|
||||||
|
|
||||||
RENDERER_HANDLER(text_set_rendering_mode)
|
RENDERER_HANDLER(text_set_rendering_mode)
|
||||||
{
|
{
|
||||||
text_state().rendering_mode = static_cast<TextRenderingMode>(args[0].as_int());
|
text_state().rendering_mode = static_cast<TextRenderingMode>(args[0].get<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
RENDERER_HANDLER(text_set_rise)
|
RENDERER_HANDLER(text_set_rise)
|
||||||
|
@ -398,11 +398,12 @@ RENDERER_HANDLER(text_show_string_array)
|
||||||
float next_shift = 0.0f;
|
float next_shift = 0.0f;
|
||||||
|
|
||||||
for (auto& element : elements) {
|
for (auto& element : elements) {
|
||||||
if (element.is_number()) {
|
if (element.has<int>()) {
|
||||||
next_shift = element.to_float();
|
next_shift = element.get<int>();
|
||||||
|
} else if (element.has<float>()) {
|
||||||
|
next_shift = element.get<float>();
|
||||||
} else {
|
} else {
|
||||||
VERIFY(element.is_object());
|
auto& obj = element.get<NonnullRefPtr<Object>>();
|
||||||
auto obj = element.as_object();
|
|
||||||
VERIFY(obj->is_string());
|
VERIFY(obj->is_string());
|
||||||
auto str = object_cast<StringObject>(obj)->string();
|
auto str = object_cast<StringObject>(obj)->string();
|
||||||
show_text(str, next_shift);
|
show_text(str, next_shift);
|
||||||
|
@ -568,7 +569,7 @@ void Renderer::show_text(String const& string, float shift)
|
||||||
|
|
||||||
RefPtr<ColorSpace> Renderer::get_color_space(Value const& value)
|
RefPtr<ColorSpace> Renderer::get_color_space(Value const& value)
|
||||||
{
|
{
|
||||||
auto name = object_cast<NameObject>(value.as_object())->name();
|
auto name = object_cast<NameObject>(value.get<NonnullRefPtr<Object>>())->name();
|
||||||
|
|
||||||
// Simple color spaces with no parameters, which can be specified directly
|
// Simple color spaces with no parameters, which can be specified directly
|
||||||
if (name == CommonNames::DeviceGray)
|
if (name == CommonNames::DeviceGray)
|
||||||
|
|
|
@ -9,52 +9,31 @@
|
||||||
|
|
||||||
namespace PDF {
|
namespace PDF {
|
||||||
|
|
||||||
Value& Value::operator=(Value const& other)
|
|
||||||
{
|
|
||||||
m_type = other.m_type;
|
|
||||||
switch (m_type) {
|
|
||||||
case Type::Empty:
|
|
||||||
case Type::Null:
|
|
||||||
break;
|
|
||||||
case Type::Bool:
|
|
||||||
m_as_bool = other.m_as_bool;
|
|
||||||
break;
|
|
||||||
case Type::Int:
|
|
||||||
m_as_int = other.m_as_int;
|
|
||||||
break;
|
|
||||||
case Type::Float:
|
|
||||||
m_as_float = other.m_as_float;
|
|
||||||
break;
|
|
||||||
case Type::Ref:
|
|
||||||
m_as_ref = other.m_as_ref;
|
|
||||||
break;
|
|
||||||
case Type::Object:
|
|
||||||
m_as_object = other.m_as_object;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String Value::to_string(int indent) const
|
String Value::to_string(int indent) const
|
||||||
{
|
{
|
||||||
switch (m_type) {
|
return visit(
|
||||||
case Type::Empty:
|
[&](Empty const&) -> String {
|
||||||
return "<empty>";
|
// Return type deduction means that we can't use implicit conversions.
|
||||||
case Type::Null:
|
return "<empty>";
|
||||||
return "null";
|
},
|
||||||
case Type::Bool:
|
[&](std::nullptr_t const&) -> String {
|
||||||
return as_bool() ? "true" : "false";
|
return "null";
|
||||||
case Type::Int:
|
},
|
||||||
return String::number(as_int());
|
[&](bool const& b) -> String {
|
||||||
case Type::Float:
|
return b ? "true" : "false";
|
||||||
return String::number(as_float());
|
},
|
||||||
case Type::Ref:
|
[&](int const& i) {
|
||||||
return String::formatted("{} {} R", as_ref_index(), as_ref_generation_index());
|
return String::number(i);
|
||||||
case Type::Object:
|
},
|
||||||
return as_object()->to_string(indent);
|
[&](float const& f) {
|
||||||
}
|
return String::number(f);
|
||||||
|
},
|
||||||
VERIFY_NOT_REACHED();
|
[&](Reference const& ref) {
|
||||||
|
return String::formatted("{} {} R", ref.as_ref_index(), ref.as_ref_generation_index());
|
||||||
|
},
|
||||||
|
[&](NonnullRefPtr<Object> const& object) {
|
||||||
|
return object->to_string(indent);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,171 +9,79 @@
|
||||||
#include <AK/Format.h>
|
#include <AK/Format.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
#include <AK/Variant.h>
|
||||||
#include <LibPDF/Forward.h>
|
#include <LibPDF/Forward.h>
|
||||||
#include <LibPDF/Object.h>
|
#include <LibPDF/Object.h>
|
||||||
#include <LibPDF/Reference.h>
|
#include <LibPDF/Reference.h>
|
||||||
|
|
||||||
namespace PDF {
|
namespace PDF {
|
||||||
|
|
||||||
class Value {
|
class Value : public Variant<Empty, std::nullptr_t, bool, int, float, Reference, NonnullRefPtr<Object>> {
|
||||||
public:
|
public:
|
||||||
|
using Variant::Variant;
|
||||||
|
|
||||||
Value()
|
Value()
|
||||||
: m_type(Type::Empty)
|
: Variant(Empty())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NullTag {
|
|
||||||
};
|
|
||||||
|
|
||||||
Value(NullTag)
|
|
||||||
: m_type(Type::Null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Value(bool b)
|
|
||||||
: m_type(Type::Bool)
|
|
||||||
{
|
|
||||||
m_as_bool = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value(int i)
|
|
||||||
: m_type(Type::Int)
|
|
||||||
{
|
|
||||||
m_as_int = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value(float f)
|
|
||||||
: m_type(Type::Float)
|
|
||||||
{
|
|
||||||
m_as_float = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value(Reference ref)
|
|
||||||
: m_type(Type::Ref)
|
|
||||||
{
|
|
||||||
m_as_ref = ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<IsObject T>
|
template<IsObject T>
|
||||||
Value(RefPtr<T> obj)
|
Value(RefPtr<T> const& refptr)
|
||||||
: m_type(obj ? Type::Object : Type::Empty)
|
: Variant(nullptr)
|
||||||
{
|
{
|
||||||
if (obj) {
|
if (refptr)
|
||||||
m_as_object = obj;
|
set<NonnullRefPtr<Object>>(*refptr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<IsObject T>
|
[[nodiscard]] String to_string(int indent = 0) const;
|
||||||
Value(NonnullRefPtr<T> obj)
|
|
||||||
: m_type(Type::Object)
|
[[nodiscard]] ALWAYS_INLINE bool has_number() const { return has<int>() || has<float>(); }
|
||||||
|
|
||||||
|
[[nodiscard]] ALWAYS_INLINE bool has_u32() const
|
||||||
{
|
{
|
||||||
m_as_object = obj;
|
return has<int>() && get<int>() >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value(Value const& other)
|
[[nodiscard]] ALWAYS_INLINE bool has_u16() const
|
||||||
{
|
{
|
||||||
*this = other;
|
return has<int>() && get<int>() >= 0 && get<int>() < 65536;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Value() = default;
|
[[nodiscard]] ALWAYS_INLINE u32 get_u32() const
|
||||||
|
|
||||||
Value& operator=(Value const& other);
|
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_empty() const { return m_type == Type::Empty; }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_null() const { return m_type == Type::Null; }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_bool() const { return m_type == Type::Bool; }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_int() const { return m_type == Type::Int; }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_float() const { return m_type == Type::Float; }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_number() const { return is_int() || is_float(); }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_ref() const { return m_type == Type::Ref; }
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_object() const { return m_type == Type::Object; }
|
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool as_bool() const
|
|
||||||
{
|
{
|
||||||
VERIFY(is_bool());
|
VERIFY(has_u32());
|
||||||
return m_as_bool;
|
return get<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE int as_int() const
|
[[nodiscard]] ALWAYS_INLINE u16 get_u16() const
|
||||||
{
|
{
|
||||||
VERIFY(is_int());
|
VERIFY(has_u16());
|
||||||
return m_as_int;
|
return get<int>();
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool is_int_type() const
|
|
||||||
{
|
|
||||||
if (!is_int())
|
|
||||||
return false;
|
|
||||||
auto as_int = static_cast<T>(m_as_int);
|
|
||||||
return as_int >= NumericLimits<T>::min() && as_int <= NumericLimits<T>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T as_int_type() const
|
|
||||||
{
|
|
||||||
VERIFY(is_int_type<T>());
|
|
||||||
return static_cast<T>(m_as_int);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE int to_int() const
|
[[nodiscard]] ALWAYS_INLINE int to_int() const
|
||||||
{
|
{
|
||||||
if (is_int())
|
if (has<int>())
|
||||||
return as_int();
|
return get<int>();
|
||||||
return static_cast<int>(as_float());
|
return static_cast<int>(get<float>());
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE float as_float() const
|
|
||||||
{
|
|
||||||
VERIFY(is_float());
|
|
||||||
return m_as_float;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE float to_float() const
|
[[nodiscard]] ALWAYS_INLINE float to_float() const
|
||||||
{
|
{
|
||||||
if (is_float())
|
if (has<float>())
|
||||||
return as_float();
|
return get<float>();
|
||||||
return static_cast<float>(as_int());
|
return static_cast<float>(get<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE u32 as_ref_index() const
|
[[nodiscard]] ALWAYS_INLINE u32 as_ref_index() const
|
||||||
{
|
{
|
||||||
VERIFY(is_ref());
|
return get<Reference>().as_ref_index();
|
||||||
return m_as_ref.as_ref_index();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE u32 as_ref_generation_index() const
|
[[nodiscard]] ALWAYS_INLINE u32 as_ref_generation_index() const
|
||||||
{
|
{
|
||||||
VERIFY(is_ref());
|
return get<Reference>().as_ref_generation_index();
|
||||||
return m_as_ref.as_ref_generation_index();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE NonnullRefPtr<Object> as_object() const { return *m_as_object; }
|
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE explicit operator bool() const { return !is_empty(); }
|
|
||||||
|
|
||||||
[[nodiscard]] String to_string(int indent = 0) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum class Type {
|
|
||||||
Empty,
|
|
||||||
Null,
|
|
||||||
Bool,
|
|
||||||
Int,
|
|
||||||
Float,
|
|
||||||
Ref,
|
|
||||||
Object,
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
bool m_as_bool;
|
|
||||||
int m_as_int;
|
|
||||||
Reference m_as_ref;
|
|
||||||
float m_as_float;
|
|
||||||
};
|
|
||||||
|
|
||||||
RefPtr<Object> m_as_object;
|
|
||||||
Type m_type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue