Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions docs/design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@
### Open tasks

- drop the last inert traces of the shipped css/js once consumers have moved
off them: `GlobalParams::odr_core_data_path`, `HtmlConfig::resource_path`,
`embed_shipped_resources`, `relative_resource_paths`,
`HtmlResource::is_shipped` and their java, python and objc mirrors, plus
`OdrAndroid.init`, `ODRGlobalParams.bootstrapFromFrameworkBundle` and the
`ODR_BUNDLE_ASSETS` / conan `bundle_assets` option, all still accepted and
all doing nothing.
off them: `GlobalParams::odr_core_data_path` and its java, python and objc
mirrors, plus `OdrAndroid.init`,
`ODRGlobalParams.bootstrapFromFrameworkBundle` and the `ODR_BUNDLE_ASSETS` /
conan `bundle_assets` option, all still accepted and all doing nothing. They
are about *finding* a data directory, which nothing does any more — unlike
`HtmlConfig::embed_shipped_resources`, `resource_path`,
`relative_resource_paths` and `HtmlResource::is_shipped`, which decide where
the compiled-in css and js land and are live again.
- drop the last inert traces of libmagic once consumers have moved off them:
`GlobalParams::libmagic_database_path` and its java, python and objc mirrors
still store and return a path nothing reads, and `ODR_WITH_LIBMAGIC` /
Expand Down
24 changes: 19 additions & 5 deletions src/odr/html.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <odr/document_path.hpp>
#include <odr/exceptions.hpp>
#include <odr/filesystem.hpp>
#include <odr/global_params.hpp>

#include <odr/internal/abstract/html_service.hpp>
#include <odr/internal/common/path.hpp>
Expand Down Expand Up @@ -57,7 +56,6 @@ HtmlConfig::HtmlConfig(std::string output_path_)
}

void HtmlConfig::init() {
resource_path = GlobalParams::odr_core_data_path();
resource_locator = html::standard_resource_locator();
}

Expand Down Expand Up @@ -248,12 +246,28 @@ HtmlService html::translate(const DecodedFile &file, const HtmlConfig &config,
HtmlResourceLocator html::standard_resource_locator() {
return [](const HtmlResource &resource,
const HtmlConfig &config) -> HtmlResourceLocation {
// only an accessible image can be embedded; everything else is linked
if (resource.is_accessible() && config.embed_images &&
resource.type() == HtmlResourceType::image) {
// what we cannot read can only be linked
if (!resource.is_accessible()) {
return resource.path();
}

if ((config.embed_shipped_resources && resource.is_shipped()) ||
(config.embed_images && resource.type() == HtmlResourceType::image)) {
return std::nullopt;
}

if (resource.is_shipped()) {
Path path = Path(config.resource_path).join(RelPath(resource.path()));
// `rebase` throws across absolute and relative; a relative one is already
// relative to the document.
if (const Path output(config.output_path.value_or(""));
config.relative_resource_paths && config.output_path.has_value() &&
path.absolute() == output.absolute()) {
path = path.rebase(output);
}
return path.string();
}

return resource.path();
};
}
Expand Down
14 changes: 8 additions & 6 deletions src/odr/html.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class HtmlResource final {
[[nodiscard]] const std::string &name() const;
[[nodiscard]] const std::string &path() const;
[[nodiscard]] const std::optional<File> &file() const;
/// @deprecated Inert: always false. The css and js are written into the
/// document, so no resource is shipped alongside it any more.
/// One of the renderer's own compiled-in css/js rather than something the
/// document carries. See @ref HtmlConfig::embed_shipped_resources.
[[nodiscard]] bool is_shipped() const;
[[nodiscard]] bool is_external() const;
[[nodiscard]] bool is_accessible() const;
Expand Down Expand Up @@ -104,14 +104,16 @@ struct HtmlConfig {

// embedding
bool embed_images{true};
/// @deprecated Inert: nothing is shipped any more, the css and js are
/// written into the document.
/// Write the renderer's own css and js into every document rather than beside
/// it as one shared file the documents link.
bool embed_shipped_resources{true};

// resources
/// @deprecated See @ref embed_shipped_resources.
/// Where linked shipped resources go, relative to the output path unless
/// named absolutely. Empty puts them beside the document.
std::string resource_path;
/// @deprecated See @ref embed_shipped_resources.
/// Link an absolute @ref resource_path relative to the document, so the
/// output stays movable.
bool relative_resource_paths{true};

// create editable output
Expand Down
48 changes: 24 additions & 24 deletions src/odr/internal/html/document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ bool is_paged_content(const Document &document, const HtmlConfig &config) {
document.document_type() == DocumentType::drawing;
}

void front(const Document &document, const WritingState &state) {
/// @p name titles the view; empty when the whole document is written as one
/// file, which no one view names.
void front(const Document &document, const WritingState &state,
const std::string &name) {
HtmlWriter &out = state.out();

const bool paged_content = is_paged_content(document, state.config());
Expand All @@ -41,15 +44,18 @@ void front(const Document &document, const WritingState &state) {
out.write_header_begin();
out.write_header_charset("UTF-8");
out.write_header_target("_blank");
out.write_header_title("odr");
out.write_header_title(
document.document_type() == DocumentType::spreadsheet && !name.empty()
? escape_text(name)
: "odr");
write_viewport_meta(out, state.config(), paged_content,
document.document_type() == DocumentType::spreadsheet
? state.config().spreadsheet_viewport_mode
: std::nullopt);

write_document_style(out);
write_document_style(state);
if (document.document_type() == DocumentType::spreadsheet) {
write_spreadsheet_style(out);
write_spreadsheet_style(state);
}

out.write_header_end();
Expand Down Expand Up @@ -87,7 +93,10 @@ void back(const Document &document, const WritingState &state) {
out.write_element_end("div");
}

write_document_script(out);
write_document_script(state);
if (document.document_type() == DocumentType::spreadsheet) {
write_spreadsheet_script(state);
}

out.write_body_end();
out.write_end();
Expand All @@ -109,7 +118,7 @@ class HtmlFragmentBase {
virtual void write_fragment(HtmlWriter &out, WritingState &state) const = 0;

void write_document(HtmlWriter &out, WritingState &state) const {
front(m_document, state);
front(m_document, state, m_name);
write_fragment(out, state);
back(m_document, state);
}
Expand Down Expand Up @@ -197,14 +206,7 @@ class HtmlServiceImpl final : public HtmlService {

warmup();

if (std::ranges::any_of(m_resources, [&path](const auto &pair) {
const auto &[resource, location] = pair;
return location.has_value() && location.value() == path;
})) {
return true;
}

return false;
return resource_at(m_resources, path) != nullptr;
}

std::string mimetype(const std::string &path) const override {
Expand All @@ -216,10 +218,9 @@ class HtmlServiceImpl final : public HtmlService {

warmup();

for (const auto &[resource, location] : m_resources) {
if (location.has_value() && location.value() == path) {
return resource.mime_type();
}
if (const odr::HtmlResource *resource = resource_at(m_resources, path);
resource != nullptr) {
return resource->mime_type();
}

throw FileNotFound("Unknown path: " + path);
Expand All @@ -236,11 +237,10 @@ class HtmlServiceImpl final : public HtmlService {

warmup();

for (const auto &[resource, location] : m_resources) {
if (location.has_value() && location.value() == path) {
resource.write_resource(out);
return;
}
if (const odr::HtmlResource *resource = resource_at(m_resources, path);
resource != nullptr) {
resource->write_resource(out);
return;
}

throw FileNotFound("Unknown path: " + path);
Expand All @@ -266,7 +266,7 @@ class HtmlServiceImpl final : public HtmlService {

WritingState state(out, config(), resources);

front(m_document, state);
front(m_document, state, "");
for (const auto &fragment : m_fragments) {
fragment->write_fragment(out, state);
}
Expand Down
65 changes: 42 additions & 23 deletions src/odr/internal/html/document_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,8 @@ void html::translate_element(const Element &element,
}

void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
state.out().write_element_begin(
"table",
HtmlElementOptions().set_attributes(HtmlAttributesVector{
{"cellpadding", "0"}, {"border", "0"}, {"cellspacing", "0"}}));
state.out().write_element_begin("table",
HtmlElementOptions().set_class("odr-sheet"));

const TableDimensions dimensions = sheet.dimensions();
std::uint32_t end_column = dimensions.columns;
Expand All @@ -101,8 +99,10 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
end_column = std::max(1u, end_column);
end_row = std::max(1u, end_row);

state.out().write_element_begin(
"col", HtmlElementOptions().set_close_type(HtmlCloseType::none));
state.out().write_element_begin("col",
HtmlElementOptions()
.set_close_type(HtmlCloseType::none)
.set_class("odr-sheet-gutter"));

for (std::uint32_t column_index = 0; column_index < end_column;
++column_index) {
Expand All @@ -116,26 +116,41 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
.set_style(translate_table_column_style(table_column_style)));
}

// No `scope`: the letters and numbers are a ruler, not headers of what they
// label.
{
state.out().write_element_begin("thead");
state.out().write_element_begin("tr");

state.out().write_element_begin("td",
HtmlElementOptions()
.set_close_type(HtmlCloseType::trailing)
.set_style("width:30px;height:20px;"));
// Under `table-layout:fixed` the first row sizes the columns, and `ch`
// resolves against the ruler's font — so the gutter width sits here rather
// than on the `<col>`.
state.out().write_element_begin(
"th",
HtmlElementOptions()
.set_inline(true)
.set_class("odr-sheet-corner")
.set_style("width:calc(" +
std::to_string(
TablePosition::to_row_string(end_row - 1).size()) +
"ch + 14px);"));
state.out().write_element_end("th");

for (std::uint32_t column_index = 0; column_index < end_column;
++column_index) {
state.out().write_element_begin(
"td", HtmlElementOptions().set_inline(true).set_style(
"text-align:center;vertical-align:middle;"));
"th", HtmlElementOptions().set_inline(true).set_class(
"odr-sheet-column-header"));
state.out().write_raw(TablePosition::to_column_string(column_index));
state.out().write_element_end("td");
state.out().write_element_end("th");
}

state.out().write_element_end("tr");
state.out().write_element_end("thead");
}

state.out().write_element_begin("tbody");

TableCursor cursor;
for (std::uint32_t row_index = cursor.row(); row_index < end_row;
row_index = cursor.row()) {
Expand All @@ -146,17 +161,20 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
translate_table_row_style(table_row_style)));

state.out().write_element_begin(
"td", HtmlElementOptions().set_inline(true).set_style([&] {
std::string style = "text-align:center;vertical-align:middle;";
if (const std::optional<Measure> height = table_row_style.height;
height.has_value()) {
style += "height:" + height->to_string() + ";";
style += "max-height:" + height->to_string() + ";";
}
return style;
}()));
"th", HtmlElementOptions()
.set_inline(true)
.set_class("odr-sheet-row-header")
.set_style([&]() -> std::optional<HtmlWritable> {
const std::optional<Measure> height =
table_row_style.height;
if (!height.has_value()) {
return std::nullopt;
}
return "height:" + height->to_string() +
";max-height:" + height->to_string() + ";";
}()));
state.out().write_raw(TablePosition::to_row_string(row_index));
state.out().write_element_end("td");
state.out().write_element_end("th");

for (std::uint32_t column_index = cursor.column();
column_index < end_column; column_index = cursor.column()) {
Expand Down Expand Up @@ -211,6 +229,7 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
cursor.add_row();
}

state.out().write_element_end("tbody");
state.out().write_element_end("table");
}

Expand Down
Loading
Loading