/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include "xlsx_table_metrics.h" #include namespace cpdoccore { namespace oox { struct region { region(int sCell, double sPos, int c, double l) : start_cell(sCell), start_pos(sPos), count(c), length(l) {} int start_cell; double start_pos; int count; double length; }; class regions { public: regions() : next_cell_(0), next_pos_(0) {} public: void add(int count, double length_pt) { region_.push_back(region(next_cell_, next_pos_, count, length_pt)); next_cell_ += count; next_pos_ += count * length_pt; } double search(int cell) { double length_pt =0; for (size_t i = 0; i < region_.size(); i++) { region & r = region_[i]; if (cell <= r.start_cell + r.count) { length_pt += (cell-r.start_cell)*r.length; break; } length_pt = r.start_pos + r.count * r.length; } if (false == region_.empty()) { if (region_.back().start_cell + region_.back().count < cell) { int offset = cell-region_.back().start_cell-region_.back().count/*-1*/; if (offset < 0) { offset =0; } length_pt += offset * region_.back().length; } } return length_pt; } std::pair search(int offset, double pos) { double skip_length =0; if (pos < 0)//cs102.ods { int c_skip = 0, i = 0; for (i = 0; i < (int)region_.size(); i++) { if (region_[i].count + c_skip > offset) break; c_skip += region_[i].count; } for (; i >= 0 && pos < 0; i--) { pos += region_[i].length * region_[i].count; offset--; } if (offset < 0) offset = 0; if (pos < 0) pos = 0; } for (size_t i = 0; i < region_.size(); i++) { region & r = region_[i]; if (r.start_cell + r.count <= offset) { skip_length = r.start_pos + r.count*r.length; continue; } if (pos + skip_length >= r.start_pos && pos + skip_length < (r.start_pos + r.count * r.length)) { skip_length += (offset - r.start_cell) * r.length; const double diff = pos + skip_length - r.start_pos; int cell = diff / r.length ; double offset_cell = diff - cell * r.length; if (offset_cell < 0) { offset_cell =0; } return std::pair(r.start_cell + cell, offset_cell); } } if (region_.size() > 0) { if (region_.back().start_cell + region_.back().count < offset) { skip_length += (offset - region_.back().start_cell - region_.back().count /*- 1*/) * region_.back().length; } region const & last_r = region_[region_.size() - 1]; const int last_cell = last_r.start_cell + last_r.count; const double last_pos = last_r.start_pos + last_r.count * last_r.length; double diff = pos + skip_length - last_r.start_pos - (last_r.count * last_r.length); if (diff < 0) diff = 0; const int cell = diff / last_r.length; double offset_cell = diff - cell * last_r.length; if (offset_cell < 0) { offset_cell = 0; } return std::pair(last_cell + cell , offset_cell); } else return std::pair(offset, pos); } std::pair search(double pos) { for (size_t i = 0; i < region_.size(); i++) { region & r = region_[i]; if (pos >= r.start_pos && pos < (r.start_pos + r.count * r.length)) { const double diff = pos - r.start_pos; const int cell = diff / r.length; double offset = diff - cell * r.length; if (offset < 0) { offset =0; } return std::pair(r.start_cell + cell, offset); } } if (region_.size() > 0) { region const & last_r = region_[region_.size() - 1]; const size_t last_cell = last_r.start_cell + last_r.count; const double last_pos = last_r.start_pos + last_r.count * last_r.length; const double diff = pos - last_pos; const int cell = diff / last_r.length; double offset = diff - cell * last_r.length; if (offset < 0) { offset =0; } return std::pair(last_cell + cell, offset); } else return std::pair(0, pos); } private: int next_cell_; double next_pos_; std::vector region_; }; class xlsx_table_metrics::Impl { public: xlsx_table_position calc(double x_pt, double y_pt) { const std::pair c = cols_.search (x_pt); const std::pair r = rows_.search (y_pt); xlsx_table_position res = {(size_t)c.first, c.second, (size_t)r.first, r.second}; return res; } xlsx_table_position calc(int offset_col, int offset_row, double x_pt, double y_pt) { std::pair c ; std::pair r ; c = cols_.search(offset_col, x_pt); r = rows_.search(offset_row, y_pt); xlsx_table_position res = {(size_t)c.first, c.second, (size_t)r.first, r.second}; return res; } xlsx_table_position calc(int last_col,int last_row) { std::pair c = cols_.search (last_col, 0); std::pair r = rows_.search (last_row, 0); xlsx_table_position res = {(size_t)c.first, c.second, (size_t)r.first, r.second}; return res; } void update_pt(int offset_col,int offset_row,double &x_pt, double &y_pt) { x_pt += cols_.search (offset_col); y_pt += rows_.search (offset_row); } void add_cols(int count, double widht_pt) { return cols_.add(count, widht_pt); } void add_rows(int count, double height_pt) { return rows_.add(count, height_pt); } private: regions cols_; regions rows_; }; xlsx_table_metrics::xlsx_table_metrics() : impl_(new xlsx_table_metrics::Impl() ) { } xlsx_table_metrics::~xlsx_table_metrics() { } xlsx_table_position xlsx_table_metrics::calc(double x_pt, double y_pt) { return impl_->calc (x_pt, y_pt); } xlsx_table_position xlsx_table_metrics::calc(int offset_col,int offset_row,double x_pt, double y_pt) { return impl_->calc(offset_col, offset_row, x_pt, y_pt); } xlsx_table_position xlsx_table_metrics::calc(int last_col,int last_row) { return impl_->calc (last_col, last_row); } void xlsx_table_metrics::update_pt(int offset_col,int offset_row,double &x_pt, double &y_pt) { return impl_->update_pt (offset_col, offset_row, x_pt, y_pt); } void xlsx_table_metrics::add_cols(int count, double width_pt) { return impl_->add_cols (count, width_pt); } void xlsx_table_metrics::add_rows(int count, double height_pt) { return impl_->add_rows (count, height_pt); } } }