differential code coverage report with master
Current view: top level - source/detail/serialization - xlsx_producer.cpp (source / functions) Coverage Total Hit UNC UBC GNC CBC
Current: coverage.info Lines: 86.1 % 2013 1734 279 6 1728
Current Date: 2025-12-15 23:01:28 Functions: 77.2 % 57 44 13 1 43
Baseline: coverage_master.info Branches: 78.7 % 4614 3633 4 1958 12 7254
Baseline Date: 2025-12-15 23:01:27

             Branch data    TLA  Line data    Source code
       1                 :                : // Copyright (c) 2014-2022 Thomas Fussell
       2                 :                : // Copyright (c) 2024-2025 xlnt-community
       3                 :                : //
       4                 :                : // Permission is hereby granted, free of charge, to any person obtaining a copy
       5                 :                : // of this software and associated documentation files (the "Software"), to deal
       6                 :                : // in the Software without restriction, including without limitation the rights
       7                 :                : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8                 :                : // copies of the Software, and to permit persons to whom the Software is
       9                 :                : // furnished to do so, subject to the following conditions:
      10                 :                : //
      11                 :                : // The above copyright notice and this permission notice shall be included in
      12                 :                : // all copies or substantial portions of the Software.
      13                 :                : //
      14                 :                : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15                 :                : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16                 :                : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17                 :                : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18                 :                : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19                 :                : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20                 :                : // THE SOFTWARE
      21                 :                : //
      22                 :                : // @license: http://www.opensource.org/licenses/mit-license.php
      23                 :                : // @author: see AUTHORS file
      24                 :                : 
      25                 :                : #include <cmath>
      26                 :                : #include <numeric> // for std::accumulate
      27                 :                : #include <string>
      28                 :                : #include <unordered_set>
      29                 :                : 
      30                 :                : #include <xlnt/cell/cell.hpp>
      31                 :                : #include <xlnt/cell/hyperlink.hpp>
      32                 :                : #include <xlnt/packaging/manifest.hpp>
      33                 :                : #include <xlnt/utils/numeric.hpp>
      34                 :                : #include <xlnt/utils/path.hpp>
      35                 :                : #include <xlnt/utils/scoped_enum_hash.hpp>
      36                 :                : #include <xlnt/workbook/workbook.hpp>
      37                 :                : #include <xlnt/workbook/workbook_view.hpp>
      38                 :                : #include <xlnt/worksheet/header_footer.hpp>
      39                 :                : #include <xlnt/worksheet/worksheet.hpp>
      40                 :                : #include <detail/constants.hpp>
      41                 :                : #include <detail/header_footer/header_footer_code.hpp>
      42                 :                : #include <detail/implementations/workbook_impl.hpp>
      43                 :                : #include <detail/serialization/custom_value_traits.hpp>
      44                 :                : #include <detail/serialization/defined_name.hpp>
      45                 :                : #include <detail/serialization/vector_streambuf.hpp>
      46                 :                : #include <detail/serialization/xlsx_producer.hpp>
      47                 :                : #include <detail/serialization/zstream.hpp>
      48                 :                : #include <detail/serialization/parsers.hpp>
      49                 :                : #include <detail/utils/string_helpers.hpp>
      50                 :                : 
      51                 :                : namespace {
      52                 :                : 
      53                 :CBC         358 : std::vector<std::pair<std::string, std::string>> core_property_namespace(xlnt::core_property type)
      54                 :                : {
      55                 :                :     using xlnt::constants;
      56                 :                :     using xlnt::core_property;
      57                 :                : 
      58         [ +  + ]:            358 :     if (type == core_property::created
      59         [ +  + ]:            286 :         || type == core_property::modified)
      60                 :                :     {
      61         [ +  + ]:            152 :         return {{constants::ns("dcterms"), "dcterms"},
      62   [ +  +  +  +  :            912 :             {constants::ns("xsi"), "xsi"}};
                   -  - ]
      63                 :                :     }
      64         [ +  + ]:            206 :     else if (type == core_property::title
      65         [ +  + ]:            196 :         || type == core_property::subject
      66         [ +  + ]:            186 :         || type == core_property::creator
      67         [ +  + ]:            110 :         || type == core_property::description)
      68                 :                :     {
      69   [ +  +  +  +  :            530 :         return {{constants::ns("dc"), "dc"}};
                +  -  - ]
      70                 :                :     }
      71         [ +  + ]:            100 :     else if (type == core_property::keywords)
      72                 :                :     {
      73         [ +  + ]:              8 :         return {{constants::ns("core-properties"), "cp"},
      74   [ +  +  +  +  :             48 :             {constants::ns("vt"), "vt"}};
                   -  - ]
      75                 :                :     }
      76                 :                : 
      77   [ +  +  +  +  :            460 :     return {{constants::ns("core-properties"), "cp"}};
                +  -  - ]
      78   [ +  +  +  +  :            876 : }
          +  +  +  +  -  
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  -  
                      - ]
      79                 :                : 
      80                 :                : } // namespace
      81                 :                : 
      82                 :                : namespace xlnt {
      83                 :                : namespace detail {
      84                 :                : 
      85                 :             44 : xlsx_producer::xlsx_producer(const workbook &target)
      86                 :             44 :     : source_(target),
      87            [ + ]:             44 :       current_part_stream_(nullptr),
      88                 :             44 :       current_cell_(nullptr),
      89                 :             88 :       current_worksheet_(nullptr)
      90                 :                : {
      91                 :             44 : }
      92                 :                : 
      93                 :             44 : xlsx_producer::~xlsx_producer()
      94                 :                : {
      95         [ +  + ]:GNC          44 :     if (current_cell_)
      96                 :                :     {
      97         [ +  - ]:              1 :         delete current_cell_;
      98                 :              1 :         current_cell_ = nullptr;
      99                 :                :     }
     100                 :                : 
     101         [ +  + ]:             44 :     if (current_worksheet_)
     102                 :                :     {
     103         [ +  - ]:              1 :         delete current_worksheet_;
     104                 :              1 :         current_worksheet_ = nullptr;
     105                 :                :     }
     106                 :                : 
     107                 :CBC          44 :     end_part();
     108                 :             44 :     archive_.reset();
     109                 :             44 : }
     110                 :                : 
     111                 :             43 : void xlsx_producer::write(std::ostream &destination)
     112                 :                : {
     113      [ +  -  - ]:             43 :     archive_.reset(new ozstream(destination));
     114                 :             43 :     populate_archive(false);
     115                 :             43 : }
     116                 :                : 
     117                 :              1 : void xlsx_producer::open(std::ostream &destination)
     118                 :                : {
     119      [ +  -  - ]:              1 :     archive_.reset(new ozstream(destination));
     120                 :              1 :     populate_archive(true);
     121                 :              1 : }
     122                 :                : 
     123                 :              2 : cell xlsx_producer::add_cell(const cell_reference &ref)
     124                 :                : {
     125                 :              2 :     current_cell_->column_ = ref.column();
     126                 :              2 :     current_cell_->row_ = ref.row();
     127                 :                : 
     128            [ + ]:              2 :     return cell(current_cell_);
     129                 :                : }
     130                 :                : 
     131                 :              1 : worksheet xlsx_producer::add_worksheet(const std::string &title)
     132                 :                : {
     133                 :              1 :     current_worksheet_->title_ = title;
     134                 :              1 :     return worksheet(current_worksheet_);
     135                 :                : }
     136                 :                : 
     137                 :                : // Part Writing Methods
     138                 :                : 
     139                 :             44 : void xlsx_producer::populate_archive(bool streaming)
     140                 :                : {
     141                 :             44 :     streaming_ = streaming;
     142                 :                : 
     143            [ + ]:             44 :     write_content_types();
     144                 :                : 
     145   [ +  +  +  + ]:            132 :     const auto root_rels = source_.manifest().relationships(path("/"));
     146      [ +  +  + ]:             44 :     write_relationships(root_rels, path("/"));
     147                 :                : 
     148         [ +  + ]:            202 :     for (auto &rel : root_rels)
     149                 :                :     {
     150                 :                :         // thumbnail is binary content so we don't want to open an xml serializer stream
     151      [ +  +  + ]:            158 :         if (rel.type() == relationship_type::thumbnail)
     152                 :                :         {
     153      [ +  +  + ]:             30 :             write_image(rel.target().path());
     154                 :             30 :             continue;
     155                 :                :         }
     156                 :                : 
     157      [ +  +  + ]:            128 :         begin_part(rel.target().path());
     158                 :                : 
     159      [ +  +  + ]:            128 :         if (rel.type() == relationship_type::core_properties)
     160                 :                :         {
     161            [ + ]:             41 :             write_core_properties(rel);
     162                 :                :         }
     163      [ +  +  + ]:             87 :         else if (rel.type() == relationship_type::extended_properties)
     164                 :                :         {
     165            [ + ]:             41 :             write_extended_properties(rel);
     166                 :                :         }
     167      [ +  +  + ]:             46 :         else if (rel.type() == relationship_type::custom_properties)
     168                 :                :         {
     169            [ + ]:              2 :             write_custom_properties(rel);
     170                 :                :         }
     171      [ +  +  - ]:             44 :         else if (rel.type() == relationship_type::office_document)
     172                 :                :         {
     173            [ + ]:             44 :             write_workbook(rel);
     174                 :                :         }
     175                 :                :     }
     176                 :                : 
     177                 :                :     // Unknown Parts
     178                 :                : 
     179                 :                :     void write_unknown_parts();
     180                 :                :     void write_unknown_relationships();
     181                 :                : 
     182                 :             44 :     end_part();
     183                 :             44 : }
     184                 :                : 
     185                 :            579 : void xlsx_producer::end_part()
     186                 :                : {
     187         [ +  + ]:            579 :     if (current_part_serializer_)
     188                 :                :     {
     189                 :            457 :         current_part_serializer_.reset();
     190                 :                :     }
     191                 :                : 
     192                 :            579 :     current_part_streambuf_.reset();
     193                 :            579 : }
     194                 :                : 
     195                 :            457 : void xlsx_producer::begin_part(const path &part)
     196                 :                : {
     197                 :            457 :     end_part();
     198            [ + ]:            457 :     current_part_streambuf_ = archive_->open(part);
     199                 :            457 :     current_part_stream_.rdbuf(current_part_streambuf_.get());
     200                 :                : 
     201   [ +  +  -  - ]:            457 :     auto xml_serializer = new xml::serializer(current_part_stream_, part.string(), 0);
     202   [ +  +  +  + ]:           2742 :     xml_serializer->xml_decl("1.0", "UTF-8", "yes");
     203                 :            457 :     current_part_serializer_.reset(xml_serializer);
     204                 :            457 : }
     205                 :                : 
     206                 :                : // Package Parts
     207                 :                : 
     208                 :             44 : void xlsx_producer::write_content_types()
     209                 :                : {
     210         [ +  + ]:             44 :     const auto content_types_path = path("[Content_Types].xml");
     211            [ + ]:             44 :     begin_part(content_types_path);
     212                 :                : 
     213                 :             44 :     const auto xmlns = "http://schemas.openxmlformats.org/package/2006/content-types";
     214                 :                : 
     215      [ +  +  + ]:            176 :     write_start_element(xmlns, "Types");
     216      [ +  +  + ]:            132 :     write_namespace(xmlns, "");
     217                 :                : 
     218   [ +  +  +  + ]:            174 :     for (const auto &extension : source_.manifest().extensions_with_default_types())
     219                 :                :     {
     220      [ +  +  + ]:            390 :         write_start_element(xmlns, "Default");
     221      [ +  +  + ]:            390 :         write_attribute("Extension", extension);
     222   [ +  +  +  + ]:            390 :         write_attribute("ContentType", source_.manifest().default_type(extension));
     223      [ +  +  + ]:            520 :         write_end_element(xmlns, "Default");
     224                 :             44 :     }
     225                 :                : 
     226   [ +  +  +  + ]:            357 :     for (const auto &part : source_.manifest().parts_with_overriden_types())
     227                 :                :     {
     228      [ +  +  + ]:           1252 :         write_start_element(xmlns, "Override");
     229   [ +  +  +  +  :            939 :         write_attribute("PartName", part.resolve(path("/")).string());
                +  +  + ]
     230   [ +  +  +  + ]:            939 :         write_attribute("ContentType", source_.manifest().override_type(part));
     231      [ +  +  + ]:           1252 :         write_end_element(xmlns, "Override");
     232                 :             44 :     }
     233                 :                : 
     234      [ +  +  + ]:            132 :     write_end_element(xmlns, "Types");
     235                 :             44 : }
     236                 :                : 
     237                 :            579 : void xlsx_producer::write_property(const std::string &name, const variant &value,
     238                 :                :     const std::string &ns, bool custom, std::size_t pid)
     239                 :                : {
     240         [ +  + ]:            579 :     if (custom)
     241                 :                :     {
     242         [ +  + ]:              2 :         write_start_element(ns, "property");
     243      [ +  +  + ]:              6 :         write_attribute("name", name);
     244                 :                :     }
     245                 :                :     else
     246                 :                :     {
     247                 :            577 :         write_start_element(ns, name);
     248                 :                :     }
     249                 :                : 
     250   [ -  +  +  +  :            579 :     switch (value.value_type())
                +  +  - ]
     251                 :                :     {
     252                 :UBC           0 :     case variant::type::null: {
     253                 :              0 :         break;
     254                 :                :     }
     255                 :                : 
     256                 :CBC          56 :     case variant::type::boolean: {
     257         [ -  + ]:             56 :         if (custom)
     258                 :                :         {
     259         [ #  # ]:UBC           0 :             write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
     260         [ #  # ]:              0 :             write_attribute("pid", pid);
     261   [ #  #  #  # ]:              0 :             write_start_element(constants::ns("vt"), "bool");
     262                 :                :         }
     263                 :                : 
     264         [ -  + ]:CBC          56 :         write_characters(value.get<bool>() ? "true" : "false");
     265                 :                : 
     266         [ -  + ]:             56 :         if (custom)
     267                 :                :         {
     268   [ #  #  #  # ]:UBC           0 :             write_end_element(constants::ns("vt"), "bool");
     269                 :                :         }
     270                 :                : 
     271                 :CBC          56 :         break;
     272                 :                :     }
     273                 :                : 
     274                 :             14 :     case variant::type::i4: {
     275         [ -  + ]:             14 :         if (custom)
     276                 :                :         {
     277         [ #  # ]:UBC           0 :             write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
     278         [ #  # ]:              0 :             write_attribute("pid", pid);
     279   [ #  #  #  # ]:              0 :             write_start_element(constants::ns("vt"), "i4");
     280                 :                :         }
     281                 :                : 
     282                 :CBC          14 :         write_characters(value.get<std::int32_t>());
     283                 :                : 
     284         [ -  + ]:             14 :         if (custom)
     285                 :                :         {
     286   [ #  #  #  # ]:UBC           0 :             write_end_element(constants::ns("vt"), "i4");
     287                 :                :         }
     288                 :                : 
     289                 :CBC          14 :         break;
     290                 :                :     }
     291                 :                : 
     292                 :            411 :     case variant::type::lpstr: {
     293         [ +  + ]:            411 :         if (custom)
     294                 :                :         {
     295         [ +  + ]:              4 :             write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
     296         [ +  + ]:              4 :             write_attribute("pid", pid);
     297   [ +  +  +  + ]:              8 :             write_start_element(constants::ns("vt"), "lpwstr");
     298                 :                :         }
     299                 :                : 
     300   [ +  +  +  +  :           1229 :         if (!custom && ns == constants::ns("dcterms") && (name == "created" || name == "modified"))
          +  +  +  +  +  
          +  +  -  +  +  
          +  +  +  +  -  
                -  -  - ]
     301                 :                :         {
     302   [ +  +  +  +  :            224 :             write_attribute(xml::qname(constants::ns("xsi"), "type"), "dcterms:W3CDTF");
                      + ]
     303                 :                :         }
     304                 :                : 
     305         [ +  + ]:            411 :         write_characters(value.get<std::string>());
     306                 :                : 
     307         [ +  + ]:            411 :         if (custom)
     308                 :                :         {
     309   [ +  +  +  + ]:              8 :             write_end_element(constants::ns("vt"), "lpwstr");
     310                 :                :         }
     311                 :                : 
     312                 :            411 :         break;
     313                 :                :     }
     314                 :                : 
     315                 :             20 :     case variant::type::date: {
     316   [ +  +  +  +  :             60 :         write_attribute(xml::qname(constants::ns("xsi"), "type"), "dcterms:W3CDTF");
                      + ]
     317      [ +  +  + ]:             20 :         write_characters(value.get<datetime>().to_iso_string());
     318                 :                : 
     319                 :             20 :         break;
     320                 :                :     }
     321                 :                : 
     322                 :             78 :     case variant::type::vector: {
     323   [ +  +  +  + ]:            234 :         write_start_element(constants::ns("vt"), "vector");
     324                 :                : 
     325            [ + ]:             78 :         auto vector = value.get<std::vector<variant>>();
     326                 :             78 :         std::unordered_set<variant::type, scoped_enum_hash<variant::type>> types;
     327                 :                : 
     328         [ +  + ]:            211 :         for (const auto &element : vector)
     329                 :                :         {
     330         [ +  + ]:            133 :             types.insert(element.value_type());
     331                 :                :         }
     332                 :                : 
     333                 :             78 :         const auto is_mixed = types.size() > 1;
     334   [ +  +  +  +  :            117 :         const auto vector_type = !is_mixed ? to_string(*types.begin()) : "variant";
             +  +  -  - ]
     335                 :                : 
     336         [ +  + ]:            156 :         write_attribute("size", vector.size());
     337      [ +  +  + ]:            234 :         write_attribute("baseType", vector_type);
     338                 :                : 
     339         [ +  + ]:            211 :         for (std::size_t i = 0; i < vector.size(); ++i)
     340                 :                :         {
     341            [ + ]:            133 :             const auto &vector_element = vector.at(i);
     342                 :                : 
     343         [ +  + ]:            133 :             if (is_mixed)
     344                 :                :             {
     345   [ +  +  +  + ]:            320 :                 write_start_element(constants::ns("vt"), "variant");
     346                 :                :             }
     347                 :                : 
     348      [ +  +  + ]:            133 :             if (vector_element.value_type() == variant::type::lpstr)
     349                 :                :             {
     350   [ +  +  +  +  :            465 :                 write_element(constants::ns("vt"), "lpstr", vector_element.get<std::string>());
                      + ]
     351                 :                :             }
     352      [ +  +  - ]:             40 :             else if (vector_element.value_type() == variant::type::i4)
     353                 :                :             {
     354   [ +  +  +  +  :            200 :                 write_element(constants::ns("vt"), "i4", vector_element.get<std::int32_t>());
                      + ]
     355                 :                :             }
     356                 :                : 
     357         [ +  + ]:            133 :             if (is_mixed)
     358                 :                :             {
     359   [ +  +  +  + ]:            320 :                 write_end_element(constants::ns("vt"), "variant");
     360                 :                :             }
     361                 :                :         }
     362                 :                : 
     363   [ +  +  +  + ]:            234 :         write_end_element(constants::ns("vt"), "vector");
     364                 :                : 
     365                 :             78 :         break;
     366                 :             78 :     }
     367                 :                :     }
     368                 :                : 
     369         [ +  + ]:            579 :     if (custom)
     370                 :                :     {
     371         [ +  + ]:              4 :         write_end_element(ns, "property");
     372                 :                :     }
     373                 :                :     else
     374                 :                :     {
     375                 :            577 :         write_end_element(ns, name);
     376                 :                :     }
     377                 :            579 : }
     378                 :                : 
     379                 :             41 : void xlsx_producer::write_core_properties(const relationship & /*rel*/)
     380                 :                : {
     381   [ +  +  +  + ]:            123 :     write_start_element(constants::ns("core-properties"), "coreProperties");
     382                 :                : 
     383            [ + ]:             41 :     auto core_properties = source_.core_properties();
     384                 :             41 :     std::unordered_map<std::string, std::string> namespaces;
     385                 :                : 
     386   [ +  +  +  + ]:            123 :     write_namespace(constants::ns("core-properties"), "cp");
     387                 :                : 
     388         [ +  + ]:            220 :     for (const auto &prop : core_properties)
     389                 :                :     {
     390      [ +  +  + ]:            438 :         for (const auto &ns : core_property_namespace(prop))
     391                 :                :         {
     392      [ +  +  + ]:            259 :             if (namespaces.count(ns.first) > 0) continue;
     393                 :                : 
     394            [ + ]:            162 :             write_namespace(ns.first, ns.second);
     395            [ + ]:            162 :             namespaces.emplace(ns);
     396                 :            179 :         }
     397                 :                :     }
     398                 :                : 
     399         [ +  + ]:            220 :     for (const auto &prop : core_properties)
     400                 :                :     {
     401         [ +  + ]:            179 :         write_property(to_string(prop), source_.core_property(prop),
     402         [ +  + ]:            358 :             core_property_namespace(prop).front().first, false, 0);
     403                 :                :     }
     404                 :                : 
     405   [ +  +  +  + ]:            123 :     write_end_element(constants::ns("core-properties"), "coreProperties");
     406                 :             41 : }
     407                 :                : 
     408                 :             41 : void xlsx_producer::write_extended_properties(const relationship & /*rel*/)
     409                 :                : {
     410   [ +  +  +  + ]:            164 :     write_start_element(constants::ns("extended-properties"), "Properties");
     411   [ +  +  +  + ]:            123 :     write_namespace(constants::ns("extended-properties"), "");
     412                 :                : 
     413                 :             41 :     if (source_.has_extended_property(extended_property::heading_pairs)
     414   [ +  +  -  +  :             41 :         || source_.has_extended_property(extended_property::titles_of_parts))
                   +  + ]
     415                 :                :     {
     416   [ +  +  +  + ]:            156 :         write_namespace(constants::ns("vt"), "vt");
     417                 :                :     }
     418                 :                : 
     419      [ +  +  + ]:            439 :     for (const auto &prop : source_.extended_properties())
     420                 :                :     {
     421   [ +  +  +  + ]:            398 :         write_property(to_string(prop), source_.extended_property(prop),
     422            [ + ]:           1194 :             constants::ns("extended-properties"), false, 0);
     423                 :             41 :     }
     424                 :                : 
     425   [ +  +  +  + ]:            123 :     write_end_element(constants::ns("extended-properties"), "Properties");
     426                 :             41 : }
     427                 :                : 
     428                 :              2 : void xlsx_producer::write_custom_properties(const relationship & /*rel*/)
     429                 :                : {
     430   [ +  +  +  + ]:              8 :     write_start_element(constants::ns("custom-properties"), "Properties");
     431   [ +  +  +  + ]:              8 :     write_namespace(constants::ns("custom-properties"), "");
     432   [ +  +  +  + ]:              6 :     write_namespace(constants::ns("vt"), "vt");
     433                 :                : 
     434                 :              2 :     auto pid = std::size_t(2); // why does this start at 2?
     435                 :                : 
     436      [ +  +  + ]:              4 :     for (const auto &prop : source_.custom_properties())
     437                 :                :     {
     438      [ +  +  + ]:              4 :         write_property(prop, source_.custom_property(prop),
     439            [ + ]:              6 :             constants::ns("custom-properties"), true, pid++);
     440                 :              2 :     }
     441                 :                : 
     442   [ +  +  +  + ]:              6 :     write_end_element(constants::ns("custom-properties"), "Properties");
     443                 :              2 : }
     444                 :                : 
     445                 :                : // Write SpreadsheetML-Specific Package Parts
     446                 :                : 
     447                 :             44 : void xlsx_producer::write_workbook(const relationship &rel)
     448                 :                : {
     449                 :             44 :     std::size_t num_visible = 0;
     450                 :             44 :     std::vector<defined_name> defined_names;
     451                 :                : 
     452   [ +  +  +  +  :             97 :     for (auto ws : source_)
                +  +  + ]
     453                 :                :     {
     454   [ +  +  +  +  :             53 :         if (!ws.has_page_setup() || ws.page_setup().sheet_state() == sheet_state::visible)
          +  +  -  +  +  
             +  -  -  - ]
     455                 :                :         {
     456                 :             53 :             num_visible++;
     457                 :                :         }
     458                 :                : 
     459      [ +  +  + ]:             53 :         auto title_ref = "'" + ws.title() + "'!";
     460                 :                : 
     461      [ +  +  + ]:             53 :         if (ws.has_auto_filter())
     462                 :                :         {
     463                 :              1 :             defined_name name;
     464            [ + ]:              1 :             name.sheet_id = ws.id();
     465            [ + ]:              1 :             name.name = "_xlnm._FilterDatabase";
     466                 :              1 :             name.hidden = true;
     467   [ +  +  +  + ]:              1 :             name.value = title_ref + range_reference::make_absolute(ws.auto_filter()).to_string();
     468            [ + ]:              1 :             defined_names.push_back(name);
     469                 :              1 :         }
     470                 :                : 
     471      [ +  +  + ]:             53 :         if (ws.has_print_area())
     472                 :                :         {
     473                 :              2 :             defined_name name;
     474            [ + ]:              2 :             name.sheet_id = ws.id();
     475            [ + ]:              2 :             name.name = "_xlnm.Print_Area";
     476                 :              2 :             name.hidden = false;
     477   [ +  +  +  + ]:              2 :             name.value = title_ref + range_reference::make_absolute(ws.print_area()).to_string();
     478            [ + ]:              2 :             defined_names.push_back(name);
     479                 :              2 :         }
     480                 :                : 
     481      [ +  +  + ]:             53 :         if (ws.has_print_titles())
     482                 :                :         {
     483                 :              3 :             defined_name name;
     484            [ + ]:              3 :             name.sheet_id = ws.id();
     485            [ + ]:              3 :             name.name = "_xlnm.Print_Titles";
     486                 :              3 :             name.hidden = false;
     487                 :                : 
     488            [ + ]:              3 :             auto cols = ws.print_title_cols();
     489         [ +  + ]:              3 :             if (cols.is_set())
     490                 :                :             {
     491   [ +  +  +  + ]:              4 :                 name.value = title_ref + "$" + cols.get().first.column_string()
     492   [ +  +  +  +  :              6 :                     + ":" + "$" + cols.get().second.column_string();
                      + ]
     493                 :                :             }
     494            [ + ]:              3 :             auto rows = ws.print_title_rows();
     495         [ +  + ]:              3 :             if (rows.is_set())
     496                 :                :             {
     497         [ +  + ]:              2 :                 if (!name.value.empty())
     498                 :                :                 {
     499            [ + ]:              1 :                     name.value.push_back(',');
     500                 :                :                 }
     501      [ +  +  + ]:              4 :                 name.value += title_ref + "$" + std::to_string(rows.get().first)
     502   [ +  +  +  +  :              6 :                     + ":" + "$" + std::to_string(rows.get().second);
                      + ]
     503                 :                :             }
     504                 :                : 
     505            [ + ]:              3 :             defined_names.push_back(name);
     506                 :              3 :         }
     507                 :             53 :     }
     508                 :                : 
     509         [ -  + ]:             44 :     if (num_visible == 0)
     510                 :                :     {
     511            [ # ]:UBC           0 :         throw no_visible_worksheets();
     512                 :                :     }
     513                 :                : 
     514   [ +  +  +  -  :CBC          46 :     static const auto &xmlns = constants::ns("workbook");
             +  +  -  - ]
     515   [ +  +  +  -  :             46 :     static const auto &xmlns_r = constants::ns("r");
             +  +  -  - ]
     516   [ +  +  +  -  :             46 :     static const auto &xmlns_s = constants::ns("spreadsheetml");
             +  +  -  - ]
     517   [ +  +  +  -  :             46 :     static const auto &xmlns_mx = constants::ns("mx");
             +  +  -  - ]
     518   [ +  +  +  -  :             46 :     static const auto &xmlns_x15ac = constants::ns("x15ac");
             +  +  -  - ]
     519   [ +  +  +  -  :             46 :     static const auto &xmlns_x15 = constants::ns("x15");
             +  +  -  - ]
     520   [ +  +  +  -  :             46 :     static const auto &xmlns_mc = constants::ns("mc");
             +  +  -  - ]
     521                 :                : 
     522         [ +  + ]:             88 :     write_start_element(xmlns, "workbook");
     523         [ +  + ]:             88 :     write_namespace(xmlns, "");
     524         [ +  + ]:             44 :     write_namespace(xmlns_r, "r");
     525                 :                : 
     526         [ +  + ]:             44 :     if (source_.d_->abs_path_.is_set())
     527                 :                :     {
     528         [ +  + ]:             34 :         write_namespace(xmlns_mc, "mc");
     529         [ +  + ]:             34 :         write_namespace(xmlns_x15, "x15");
     530      [ +  +  + ]:             34 :         write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x15");
     531                 :                :     }
     532                 :                : 
     533      [ +  +  + ]:             44 :     if (source_.has_file_version())
     534                 :                :     {
     535         [ +  + ]:             40 :         write_start_element(xmlns, "fileVersion");
     536                 :                : 
     537      [ +  +  + ]:            120 :         write_attribute("appName", source_.app_name());
     538      [ +  +  + ]:             80 :         write_attribute("lastEdited", source_.last_edited());
     539      [ +  +  + ]:             80 :         write_attribute("lowestEdited", source_.lowest_edited());
     540      [ +  +  + ]:            120 :         write_attribute("rupBuild", source_.rup_build());
     541                 :                : 
     542         [ +  + ]:             80 :         write_end_element(xmlns, "fileVersion");
     543                 :                :     }
     544                 :                : 
     545         [ +  + ]:             44 :     write_start_element(xmlns, "workbookPr");
     546                 :                : 
     547      [ +  -  + ]:             44 :     if (source_.has_code_name())
     548                 :                :     {
     549      [ #  #  # ]:UBC           0 :         write_attribute("codeName", source_.code_name());
     550                 :                :     }
     551                 :                : 
     552      [ +  +  + ]:CBC          44 :     if (source_.base_date() == calendar::mac_1904)
     553                 :                :     {
     554         [ +  + ]:              2 :         write_attribute("date1904", "1");
     555                 :                :     }
     556                 :                : 
     557         [ +  + ]:             44 :     write_end_element(xmlns, "workbookPr");
     558                 :                : 
     559         [ +  + ]:             44 :     if (source_.d_->abs_path_.is_set())
     560                 :                :     {
     561         [ +  + ]:             34 :         write_start_element(xmlns_mc, "AlternateContent");
     562         [ +  + ]:             34 :         write_namespace(xmlns_mc, "mc");
     563         [ +  + ]:             34 :         write_start_element(xmlns_mc, "Choice");
     564         [ +  + ]:             34 :         write_attribute("Requires", "x15");
     565         [ +  + ]:             34 :         write_start_element(xmlns_x15ac, "absPath");
     566         [ +  + ]:             17 :         write_namespace(xmlns_x15ac, "x15ac");
     567   [ +  +  +  + ]:             51 :         write_attribute("url", source_.d_->abs_path_.get());
     568         [ +  + ]:             34 :         write_end_element(xmlns_x15ac, "absPath");
     569         [ +  + ]:             34 :         write_end_element(xmlns_mc, "Choice");
     570         [ +  + ]:             34 :         write_end_element(xmlns_mc, "AlternateContent");
     571                 :                :     }
     572                 :                : 
     573      [ +  +  + ]:             44 :     if (source_.has_view())
     574                 :                :     {
     575         [ +  + ]:             82 :         write_start_element(xmlns, "bookViews");
     576         [ +  + ]:             41 :         write_start_element(xmlns, "workbookView");
     577                 :                : 
     578            [ + ]:             41 :         const auto &view = source_.view();
     579                 :                : 
     580   [ +  +  +  +  :             41 :         if (view.active_tab.is_set() && view.active_tab.get() != std::size_t(0))
                +  +  + ]
     581                 :                :         {
     582      [ +  +  + ]:              3 :             write_attribute("activeTab", view.active_tab.get());
     583                 :                :         }
     584                 :                : 
     585         [ -  + ]:             41 :         if (!view.auto_filter_date_grouping)
     586                 :                :         {
     587      [ #  #  # ]:UBC           0 :             write_attribute("autoFilterDateGrouping", write_bool(view.auto_filter_date_grouping));
     588                 :                :         }
     589                 :                : 
     590         [ -  + ]:CBC          41 :         if (view.first_sheet.is_set())
     591                 :                :         {
     592      [ #  #  # ]:UBC           0 :             write_attribute("firstSheet", view.first_sheet.get());
     593                 :                :         }
     594                 :                : 
     595         [ -  + ]:CBC          41 :         if (view.minimized)
     596                 :                :         {
     597      [ #  #  # ]:UBC           0 :             write_attribute("minimized", write_bool(view.minimized));
     598                 :                :         }
     599                 :                : 
     600         [ -  + ]:CBC          41 :         if (!view.show_horizontal_scroll)
     601                 :                :         {
     602      [ #  #  # ]:UBC           0 :             write_attribute("showHorizontalScroll", write_bool(view.show_horizontal_scroll));
     603                 :                :         }
     604                 :                : 
     605         [ -  + ]:CBC          41 :         if (!view.show_sheet_tabs)
     606                 :                :         {
     607      [ #  #  # ]:UBC           0 :             write_attribute("showSheetTabs", write_bool(view.show_sheet_tabs));
     608                 :                :         }
     609                 :                : 
     610         [ -  + ]:CBC          41 :         if (!view.show_vertical_scroll)
     611                 :                :         {
     612      [ #  #  # ]:UBC           0 :             write_attribute("showVerticalScroll", write_bool(view.show_vertical_scroll));
     613                 :                :         }
     614                 :                : 
     615         [ -  + ]:CBC          41 :         if (!view.visible)
     616                 :                :         {
     617      [ #  #  # ]:UBC           0 :             write_attribute("visibility", write_bool(view.visible));
     618                 :                :         }
     619                 :                : 
     620         [ +  - ]:CBC          41 :         if (view.x_window.is_set())
     621                 :                :         {
     622      [ +  +  + ]:            123 :             write_attribute("xWindow", view.x_window.get());
     623                 :                :         }
     624                 :                : 
     625         [ +  - ]:             41 :         if (view.y_window.is_set())
     626                 :                :         {
     627      [ +  +  + ]:            123 :             write_attribute("yWindow", view.y_window.get());
     628                 :                :         }
     629                 :                : 
     630         [ +  - ]:             41 :         if (view.window_width.is_set())
     631                 :                :         {
     632      [ +  +  + ]:            123 :             write_attribute("windowWidth", view.window_width.get());
     633                 :                :         }
     634                 :                : 
     635         [ +  - ]:             41 :         if (view.window_height.is_set())
     636                 :                :         {
     637      [ +  +  + ]:            123 :             write_attribute("windowHeight", view.window_height.get());
     638                 :                :         }
     639                 :                : 
     640         [ +  + ]:             41 :         if (view.tab_ratio.is_set())
     641                 :                :         {
     642      [ +  +  + ]:             96 :             write_attribute("tabRatio", view.tab_ratio.get());
     643                 :                :         }
     644                 :                : 
     645         [ +  + ]:             82 :         write_end_element(xmlns, "workbookView");
     646         [ +  + ]:             41 :         write_end_element(xmlns, "bookViews");
     647                 :             41 :     }
     648                 :                : 
     649         [ +  + ]:             44 :     write_start_element(xmlns, "sheets");
     650                 :                : 
     651                 :                : #pragma clang diagnostic push
     652                 :                : #pragma clang diagnostic ignored "-Wrange-loop-analysis"
     653   [ +  +  +  +  :             97 :     for (const auto ws : source_)
                +  +  + ]
     654                 :                :     {
     655      [ +  +  + ]:             53 :         auto sheet_rel_id = source_.d_->sheet_title_rel_id_map_[ws.title()];
     656      [ +  +  + ]:             53 :         auto sheet_rel = source_.d_->manifest_.relationship(rel.target().path(), sheet_rel_id);
     657                 :                : 
     658         [ +  + ]:             53 :         write_start_element(xmlns, "sheet");
     659      [ +  +  + ]:            159 :         write_attribute("name", ws.title());
     660      [ +  +  + ]:            106 :         write_attribute("sheetId", ws.id());
     661                 :                : 
     662   [ +  +  +  +  :             53 :         if (ws.has_page_setup() && ws.sheet_state() == xlnt::sheet_state::hidden)
             -  +  -  + ]
     663                 :                :         {
     664         [ #  # ]:UBC           0 :             write_attribute("state", "hidden");
     665                 :                :         }
     666                 :                : 
     667   [ +  +  +  + ]:CBC         159 :         write_attribute(xml::qname(xmlns_r, "id"), sheet_rel_id);
     668         [ +  + ]:             53 :         write_end_element(xmlns, "sheet");
     669                 :             53 :     }
     670                 :                : #pragma clang diagnostic pop
     671                 :                : 
     672         [ +  + ]:             44 :     write_end_element(xmlns, "sheets");
     673                 :                : 
     674         [ +  + ]:             44 :     if (!defined_names.empty())
     675                 :                :     {
     676         [ +  + ]:              1 :         write_start_element(xmlns, "definedNames");
     677         [ +  + ]:              7 :         for (const auto & name : defined_names)
     678                 :                :         {
     679         [ +  + ]:              6 :             write_start_element(xmlns, "definedName");
     680      [ +  +  + ]:             18 :             write_attribute("name", name.name);
     681         [ +  + ]:              6 :             if (name.hidden)
     682                 :                :             {
     683      [ +  +  + ]:              3 :                 write_attribute("hidden", write_bool(true));
     684                 :                :             }
     685                 :                : 
     686         [ +  - ]:              6 :             if (name.sheet_id.is_set())
     687                 :                :             {
     688   [ +  +  +  + ]:             18 :                 write_attribute("localSheetId", std::to_string(name.sheet_id.get() - 1)); // 0-indexed for some reason
     689                 :                :             }
     690         [ +  + ]:              6 :             write_characters(name.value);
     691         [ +  + ]:             12 :             write_end_element(xmlns, "definedName");
     692                 :                :         }
     693         [ +  + ]:              2 :         write_end_element(xmlns, "definedNames");
     694                 :                :     }
     695                 :                : 
     696      [ +  +  + ]:             44 :     if (source_.has_calculation_properties())
     697                 :                :     {
     698         [ +  + ]:             41 :         write_start_element(xmlns, "calcPr");
     699      [ +  +  + ]:             82 :         write_attribute("calcId", source_.calculation_properties().calc_id);
     700                 :                :         //write_attribute("calcMode", "auto");
     701                 :                :         //write_attribute("fullCalcOnLoad", "1");
     702   [ +  +  +  + ]:            123 :         write_attribute("concurrentCalc", write_bool(source_.calculation_properties().concurrent_calc));
     703         [ +  + ]:             82 :         write_end_element(xmlns, "calcPr");
     704                 :                :     }
     705                 :                : 
     706      [ +  -  + ]:             44 :     if (!source_.named_ranges().empty())
     707                 :                :     {
     708         [ #  # ]:UBC           0 :         write_start_element(xmlns, "definedNames");
     709                 :                : 
     710      [ #  #  # ]:              0 :         for (auto &named_range : source_.named_ranges())
     711                 :                :         {
     712         [ #  # ]:              0 :             write_start_element(xmlns_s, "definedName");
     713         [ #  # ]:              0 :             write_namespace(xmlns_s, "s");
     714      [ #  #  # ]:              0 :             write_attribute("name", named_range.name());
     715            [ # ]:              0 :             const auto &target = named_range.targets().front();
     716   [ #  #  #  #  :              0 :             write_characters("'" + target.first.title() + "\'!" + target.second.to_string());
                   #  # ]
     717         [ #  # ]:              0 :             write_end_element(xmlns_s, "definedName");
     718                 :              0 :         }
     719                 :                : 
     720         [ #  # ]:              0 :         write_end_element(xmlns, "definedNames");
     721                 :                :     }
     722                 :                : 
     723         [ +  + ]:CBC          44 :     if (source_.d_->arch_id_flags_.is_set())
     724                 :                :     {
     725         [ +  + ]:             20 :         write_start_element(xmlns, "extLst");
     726         [ +  + ]:             20 :         write_start_element(xmlns, "ext");
     727         [ +  + ]:             20 :         write_namespace(xmlns_mx, "mx");
     728         [ +  + ]:             20 :         write_attribute("uri", "{7523E5D3-25F3-A5E0-1632-64F254C22452}");
     729         [ +  + ]:             10 :         write_start_element(xmlns_mx, "ArchID");
     730      [ +  +  + ]:             30 :         write_attribute("Flags", source_.d_->arch_id_flags_.get());
     731         [ +  + ]:             20 :         write_end_element(xmlns_mx, "ArchID");
     732         [ +  + ]:             20 :         write_end_element(xmlns, "ext");
     733         [ +  + ]:             20 :         write_end_element(xmlns, "extLst");
     734                 :                :     }
     735                 :                : 
     736         [ +  + ]:             44 :     write_end_element(xmlns, "workbook");
     737                 :                : 
     738   [ +  +  +  + ]:             44 :     auto workbook_rels = source_.manifest().relationships(rel.target().path());
     739      [ +  +  + ]:             44 :     write_relationships(workbook_rels, rel.target().path());
     740                 :                : 
     741         [ +  + ]:            216 :     for (const auto &child_rel : workbook_rels)
     742                 :                :     {
     743      [ +  +  + ]:            172 :         if (child_rel.type() == relationship_type::calculation_chain)
     744                 :                :         {
     745                 :                :             // We don't yet have a VBA interpreter which can evaluate formulas.
     746                 :                :             // If we write an outdated calculate chain, Excel will treat the XLSX
     747                 :                :             // as corrupt. As a workaround, we keep the relationship but don't
     748                 :                :             // write the calculation chain file so Excel will recalculate all formulae
     749                 :                :             // on load.
     750                 :              6 :             continue;
     751                 :                :         }
     752                 :                : 
     753      [ +  +  + ]:            167 :         auto child_target_path = child_rel.target().path();
     754   [ +  +  +  + ]:            167 :         path archive_path(child_rel.source().path().parent().append(child_target_path));
     755                 :                : 
     756                 :                :         // write binary
     757      [ +  +  + ]:            167 :         if (child_rel.type() == relationship_type::vbaproject)
     758                 :                :         {
     759            [ + ]:              1 :             write_binary(archive_path);
     760                 :              1 :             continue;
     761                 :                :         }
     762                 :                : 
     763                 :                :         // write xml
     764            [ + ]:            166 :         begin_part(archive_path);
     765                 :                : 
     766   [ +  -  -  -  :            166 :         switch (child_rel.type())
          -  -  -  +  -  
          +  +  -  +  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                -  -  - ]
     767                 :                :         {
     768                 :UBC           0 :         case relationship_type::chartsheet:
     769            [ # ]:              0 :             write_chartsheet(child_rel);
     770                 :              0 :             break;
     771                 :                : 
     772                 :              0 :         case relationship_type::connections:
     773            [ # ]:              0 :             write_connections(child_rel);
     774                 :              0 :             break;
     775                 :                : 
     776                 :              0 :         case relationship_type::custom_xml_mappings:
     777            [ # ]:              0 :             write_custom_xml_mappings(child_rel);
     778                 :              0 :             break;
     779                 :                : 
     780                 :              0 :         case relationship_type::dialogsheet:
     781            [ # ]:              0 :             write_dialogsheet(child_rel);
     782                 :              0 :             break;
     783                 :                : 
     784                 :              0 :         case relationship_type::external_workbook_references:
     785            [ # ]:              0 :             write_external_workbook_references(child_rel);
     786                 :              0 :             break;
     787                 :                : 
     788                 :              0 :         case relationship_type::pivot_table:
     789            [ # ]:              0 :             write_pivot_table(child_rel);
     790                 :              0 :             break;
     791                 :                : 
     792                 :CBC          30 :         case relationship_type::shared_string_table:
     793            [ + ]:             30 :             write_shared_string_table(child_rel);
     794                 :             30 :             break;
     795                 :                : 
     796                 :UBC           0 :         case relationship_type::shared_workbook_revision_headers:
     797            [ # ]:              0 :             write_shared_workbook_revision_headers(child_rel);
     798                 :              0 :             break;
     799                 :                : 
     800                 :CBC          42 :         case relationship_type::stylesheet:
     801            [ + ]:             42 :             write_styles(child_rel);
     802                 :             42 :             break;
     803                 :                : 
     804                 :             41 :         case relationship_type::theme:
     805            [ + ]:             41 :             write_theme(child_rel);
     806                 :             41 :             break;
     807                 :                : 
     808                 :UBC           0 :         case relationship_type::volatile_dependencies:
     809            [ # ]:              0 :             write_volatile_dependencies(child_rel);
     810                 :              0 :             break;
     811                 :                : 
     812                 :CBC          53 :         case relationship_type::worksheet:
     813            [ + ]:             53 :             write_worksheet(child_rel);
     814                 :             53 :             break;
     815                 :                : 
     816                 :UBC           0 :         case relationship_type::calculation_chain:
     817                 :              0 :             break;
     818                 :              0 :         case relationship_type::office_document:
     819                 :              0 :             break;
     820                 :              0 :         case relationship_type::thumbnail:
     821                 :              0 :             break;
     822                 :              0 :         case relationship_type::extended_properties:
     823                 :              0 :             break;
     824                 :              0 :         case relationship_type::core_properties:
     825                 :              0 :             break;
     826                 :              0 :         case relationship_type::hyperlink:
     827                 :              0 :             break;
     828                 :              0 :         case relationship_type::comments:
     829                 :              0 :             break;
     830                 :              0 :         case relationship_type::vml_drawing:
     831                 :              0 :             break;
     832                 :              0 :         case relationship_type::unknown:
     833                 :              0 :             break;
     834                 :              0 :         case relationship_type::custom_properties:
     835                 :              0 :             break;
     836                 :              0 :         case relationship_type::printer_settings:
     837                 :              0 :             break;
     838                 :              0 :         case relationship_type::custom_property:
     839                 :              0 :             break;
     840                 :              0 :         case relationship_type::drawings:
     841                 :              0 :             break;
     842                 :              0 :         case relationship_type::pivot_table_cache_definition:
     843                 :              0 :             break;
     844                 :              0 :         case relationship_type::pivot_table_cache_records:
     845                 :              0 :             break;
     846                 :              0 :         case relationship_type::query_table:
     847                 :              0 :             break;
     848                 :              0 :         case relationship_type::shared_workbook:
     849                 :              0 :             break;
     850                 :              0 :         case relationship_type::revision_log:
     851                 :              0 :             break;
     852                 :              0 :         case relationship_type::shared_workbook_user_data:
     853                 :              0 :             break;
     854                 :              0 :         case relationship_type::single_cell_table_definitions:
     855                 :              0 :             break;
     856                 :              0 :         case relationship_type::table_definition:
     857                 :              0 :             break;
     858                 :              0 :         case relationship_type::vbaproject:
     859                 :              0 :             break;
     860                 :              0 :         case relationship_type::image:
     861                 :              0 :             break;
     862                 :                :         }
     863   [ +  +  +  + ]:CBC         168 :     }
     864                 :             44 : }
     865                 :                : 
     866                 :                : // Write Workbook Relationship Target Parts
     867                 :                : 
     868                 :UBC           0 : void xlsx_producer::write_chartsheet(const relationship & /*rel*/)
     869                 :                : {
     870   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "chartsheet");
     871   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "chartsheet");
     872                 :              0 : }
     873                 :                : 
     874                 :              0 : void xlsx_producer::write_connections(const relationship & /*rel*/)
     875                 :                : {
     876   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "connections");
     877   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "connections");
     878                 :              0 : }
     879                 :                : 
     880                 :              0 : void xlsx_producer::write_custom_xml_mappings(const relationship & /*rel*/)
     881                 :                : {
     882   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "MapInfo");
     883   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "MapInfo");
     884                 :              0 : }
     885                 :                : 
     886                 :              0 : void xlsx_producer::write_dialogsheet(const relationship & /*rel*/)
     887                 :                : {
     888   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "dialogsheet");
     889   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "dialogsheet");
     890                 :              0 : }
     891                 :                : 
     892                 :              0 : void xlsx_producer::write_external_workbook_references(const relationship & /*rel*/)
     893                 :                : {
     894   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "externalLink");
     895   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "externalLink");
     896                 :              0 : }
     897                 :                : 
     898                 :              0 : void xlsx_producer::write_pivot_table(const relationship & /*rel*/)
     899                 :                : {
     900   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "pivotTableDefinition");
     901   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "pivotTableDefinition");
     902                 :              0 : }
     903                 :                : 
     904                 :CBC         350 : void xlsx_producer::write_rich_text(const std::string &ns, const xlnt::rich_text &text)
     905                 :                : {
     906   [ +  +  -  +  :            350 :     if (text.runs().size() == 1 && !text.runs().at(0).second.is_set())
          +  +  +  +  -  
          +  -  +  +  -  
                -  -  - ]
     907                 :                :     {
     908         [ +  + ]:            334 :         write_start_element(ns, "t");
     909      [ +  +  + ]:            334 :         write_characters(text.plain_text(), text.runs().front().preserve_space);
     910         [ +  + ]:            668 :         write_end_element(ns, "t");
     911                 :                :     }
     912                 :                :     else
     913                 :                :     {
     914      [ +  +  + ]:             32 :         for (const auto &run : text.runs())
     915                 :                :         {
     916         [ +  + ]:             16 :             write_start_element(ns, "r");
     917                 :                : 
     918         [ +  - ]:             16 :             if (run.second.is_set())
     919                 :                :             {
     920         [ +  + ]:             16 :                 write_start_element(ns, "rPr");
     921                 :                : 
     922   [ +  +  +  - ]:             16 :                 if (run.second.get().bold())
     923                 :                :                 {
     924         [ +  + ]:             32 :                     write_start_element(ns, "b");
     925         [ +  + ]:             32 :                     write_end_element(ns, "b");
     926                 :                :                 }
     927                 :                : 
     928   [ +  +  +  - ]:             16 :                 if (run.second.get().has_size())
     929                 :                :                 {
     930         [ +  + ]:             16 :                     write_start_element(ns, "sz");
     931   [ +  +  +  + ]:             48 :                     write_attribute<double>("val", run.second.get().size());
     932         [ +  + ]:             32 :                     write_end_element(ns, "sz");
     933                 :                :                 }
     934                 :                : 
     935   [ +  +  +  - ]:             16 :                 if (run.second.get().has_color())
     936                 :                :                 {
     937         [ +  + ]:             16 :                     write_start_element(ns, "color");
     938      [ +  +  + ]:             16 :                     write_color(run.second.get().color());
     939         [ +  + ]:             32 :                     write_end_element(ns, "color");
     940                 :                :                 }
     941                 :                : 
     942   [ +  +  +  - ]:             16 :                 if (run.second.get().has_name())
     943                 :                :                 {
     944         [ +  + ]:             16 :                     write_start_element(ns, "rFont");
     945   [ +  +  +  +  :             48 :                     write_attribute("val", run.second.get().name());
                      + ]
     946         [ +  + ]:             32 :                     write_end_element(ns, "rFont");
     947                 :                :                 }
     948                 :                : 
     949   [ +  +  -  + ]:             16 :                 if (run.second.get().has_family())
     950                 :                :                 {
     951         [ #  # ]:UBC           0 :                     write_start_element(ns, "family");
     952   [ #  #  #  # ]:              0 :                     write_attribute("val", run.second.get().family());
     953         [ #  # ]:              0 :                     write_end_element(ns, "family");
     954                 :                :                 }
     955                 :                : 
     956   [ +  +  -  + ]:CBC          16 :                 if (run.second.get().has_scheme())
     957                 :                :                 {
     958         [ #  # ]:UBC           0 :                     write_start_element(ns, "scheme");
     959   [ #  #  #  #  :              0 :                     write_attribute("val", run.second.get().scheme());
                      # ]
     960         [ #  # ]:              0 :                     write_end_element(ns, "scheme");
     961                 :                :                 }
     962                 :                : 
     963         [ +  + ]:CBC          32 :                 write_end_element(ns, "rPr");
     964                 :                :             }
     965                 :                : 
     966      [ +  +  + ]:             48 :             write_element(ns, "t", run.first, run.preserve_space);
     967         [ +  + ]:             32 :             write_end_element(ns, "r");
     968                 :             16 :         }
     969                 :                :     }
     970                 :                : 
     971      [ +  +  + ]:            351 :     for (const auto &run : text.phonetic_runs())
     972                 :                :     {
     973         [ +  + ]:              1 :         write_start_element(ns, "rPh");
     974         [ +  + ]:              2 :         write_attribute("sb", run.start);
     975         [ +  + ]:              3 :         write_attribute("eb", run.end);
     976         [ +  + ]:              1 :         write_start_element(ns, "t");
     977         [ +  + ]:              1 :         write_characters(run.text, run.preserve_space);
     978         [ +  + ]:              2 :         write_end_element(ns, "t");
     979         [ +  + ]:              2 :         write_end_element(ns, "rPh");
     980                 :            350 :     }
     981                 :                : 
     982         [ +  + ]:            350 :     if (text.has_phonetic_properties())
     983                 :                :     {
     984                 :              3 :         const auto &phonetic_properties = text.phonetic_properties();
     985                 :                : 
     986         [ +  + ]:              3 :         write_start_element(ns, "phoneticPr");
     987         [ +  + ]:              6 :         write_attribute("fontId", phonetic_properties.font_id());
     988                 :                : 
     989         [ +  + ]:              3 :         if (text.phonetic_properties().has_type())
     990                 :                :         {
     991                 :              2 :             const auto type = phonetic_properties.type();
     992   [ +  +  +  + ]:              6 :             write_attribute("type", phonetic_properties.type_as_string(type));
     993                 :                :         }
     994                 :                : 
     995         [ -  + ]:              3 :         if (text.phonetic_properties().has_alignment())
     996                 :                :         {
     997                 :UBC           0 :             const auto alignment = phonetic_properties.alignment();
     998   [ #  #  #  # ]:              0 :             write_attribute("alignment", phonetic_properties.alignment_as_string(alignment));
     999                 :                :         }
    1000                 :                : 
    1001         [ +  + ]:CBC           6 :         write_end_element(ns, "phoneticPr");
    1002                 :                :     }
    1003                 :            350 : }
    1004                 :                : 
    1005                 :             30 : void xlsx_producer::write_shared_string_table(const relationship & /*rel*/)
    1006                 :                : {
    1007   [ +  +  +  -  :             32 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    1008                 :                : 
    1009         [ +  + ]:             60 :     write_start_element(xmlns, "sst");
    1010         [ +  + ]:             30 :     write_namespace(xmlns, "");
    1011                 :                : 
    1012                 :                :     // todo: is there a more elegant way to get this number?
    1013                 :             30 :     std::size_t string_count = 0;
    1014                 :                : 
    1015   [ +  +  +  +  :             67 :     for (const auto ws : source_)
                +  +  + ]
    1016                 :                :     {
    1017            [ + ]:             37 :         auto dimension = ws.calculate_dimension();
    1018            [ + ]:             37 :         auto current_cell = dimension.top_left();
    1019                 :                : 
    1020   [ +  +  +  +  :           1677 :         while (current_cell.row() <= dimension.bottom_right().row())
                      + ]
    1021                 :                :         {
    1022   [ +  +  +  +  :           4244 :             while (current_cell.column() <= dimension.bottom_right().column())
                   +  + ]
    1023                 :                :             {
    1024            [ + ]:           2604 :                 auto c_iter = ws.d_->cell_map_.find(current_cell);
    1025   [ +  +  +  +  :           2604 :                 if (c_iter != ws.d_->cell_map_.end() && c_iter->second.type_ == cell_type::shared_string)
                   +  + ]
    1026                 :                :                 {
    1027                 :            732 :                     ++string_count;
    1028                 :                :                 }
    1029                 :                : 
    1030      [ +  +  + ]:           2604 :                 current_cell.column_index(current_cell.column_index() + 1);
    1031                 :                :             }
    1032                 :                : 
    1033         [ +  + ]:           1640 :             current_cell.row(current_cell.row() + 1);
    1034   [ +  +  +  + ]:           1640 :             current_cell.column_index(dimension.top_left().column_index());
    1035                 :                :         }
    1036                 :                :     }
    1037                 :                : 
    1038         [ +  + ]:             30 :     write_attribute("count", string_count);
    1039         [ +  + ]:             60 :     write_attribute("uniqueCount", source_.shared_strings().size());
    1040                 :                : 
    1041      [ +  +  + ]:            364 :     for (const auto &text : source_.shared_strings())
    1042                 :                :     {
    1043         [ +  + ]:            334 :         write_start_element(xmlns, "si");
    1044            [ + ]:            334 :         write_rich_text(xmlns, text);
    1045         [ +  + ]:            668 :         write_end_element(xmlns, "si");
    1046                 :                :     }
    1047                 :                : 
    1048         [ +  + ]:             30 :     write_end_element(xmlns, "sst");
    1049                 :             30 : }
    1050                 :                : 
    1051                 :UBC           0 : void xlsx_producer::write_shared_workbook_revision_headers(const relationship & /*rel*/)
    1052                 :                : {
    1053   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "headers");
    1054   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "headers");
    1055                 :              0 : }
    1056                 :                : 
    1057                 :              0 : void xlsx_producer::write_shared_workbook(const relationship & /*rel*/)
    1058                 :                : {
    1059   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "revisions");
    1060   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "revisions");
    1061                 :              0 : }
    1062                 :                : 
    1063                 :              0 : void xlsx_producer::write_shared_workbook_user_data(const relationship & /*rel*/)
    1064                 :                : {
    1065   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "users");
    1066   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "users");
    1067                 :              0 : }
    1068                 :                : 
    1069                 :CBC         203 : void xlsx_producer::write_font(const font &f)
    1070                 :                : {
    1071   [ +  +  +  -  :            205 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    1072                 :                : 
    1073         [ +  + ]:            203 :     write_start_element(xmlns, "font");
    1074                 :                : 
    1075         [ +  + ]:            203 :     if (f.bold())
    1076                 :                :     {
    1077         [ +  + ]:             94 :         write_start_element(xmlns, "b");
    1078         [ +  + ]:             94 :         write_end_element(xmlns, "b");
    1079                 :                :     }
    1080                 :                : 
    1081         [ +  + ]:            203 :     if (f.italic())
    1082                 :                :     {
    1083         [ +  + ]:             40 :         write_start_element(xmlns, "i");
    1084         [ +  + ]:             40 :         write_end_element(xmlns, "i");
    1085                 :                :     }
    1086                 :                : 
    1087         [ +  + ]:            203 :     if (f.strikethrough())
    1088                 :                :     {
    1089         [ +  + ]:             16 :         write_start_element(xmlns, "strike");
    1090         [ +  + ]:             16 :         write_end_element(xmlns, "strike");
    1091                 :                :     }
    1092                 :                : 
    1093         [ +  + ]:            203 :     if (f.underlined())
    1094                 :                :     {
    1095         [ +  + ]:             29 :         write_start_element(xmlns, "u");
    1096         [ +  + ]:             29 :         if (f.underline() != font::underline_style::single)
    1097                 :                :         {
    1098         [ +  + ]:             60 :             write_attribute("val", f.underline());
    1099                 :                :         }
    1100         [ +  + ]:             58 :         write_end_element(xmlns, "u");
    1101                 :                :     }
    1102                 :                : 
    1103         [ +  + ]:            203 :     if (f.superscript())
    1104                 :                :     {
    1105         [ +  + ]:              8 :         write_start_element(xmlns, "vertAlign");
    1106         [ +  + ]:              8 :         write_attribute("val", "superscript");
    1107         [ +  + ]:              8 :         write_end_element(xmlns, "vertAlign");
    1108                 :                :     }
    1109         [ +  + ]:            199 :     else if (f.subscript())
    1110                 :                :     {
    1111         [ +  + ]:             16 :         write_start_element(xmlns, "vertAlign");
    1112         [ +  + ]:             16 :         write_attribute("val", "subscript");
    1113         [ +  + ]:             16 :         write_end_element(xmlns, "vertAlign");
    1114                 :                :     }
    1115                 :                : 
    1116         [ +  + ]:            203 :     if (f.has_size())
    1117                 :                :     {
    1118         [ +  + ]:            201 :         write_start_element(xmlns, "sz");
    1119         [ +  + ]:            603 :         write_attribute<double>("val", f.size());
    1120         [ +  + ]:            402 :         write_end_element(xmlns, "sz");
    1121                 :                :     }
    1122                 :                : 
    1123         [ +  + ]:            203 :     if (f.has_color())
    1124                 :                :     {
    1125         [ +  + ]:            193 :         write_start_element(xmlns, "color");
    1126         [ +  + ]:            193 :         write_color(f.color());
    1127         [ +  + ]:            386 :         write_end_element(xmlns, "color");
    1128                 :                :     }
    1129                 :                : 
    1130         [ +  + ]:            203 :     if (f.has_name())
    1131                 :                :     {
    1132         [ +  + ]:            202 :         write_start_element(xmlns, "name");
    1133   [ +  +  +  + ]:            606 :         write_attribute("val", f.name());
    1134         [ +  + ]:            404 :         write_end_element(xmlns, "name");
    1135                 :                :     }
    1136                 :                : 
    1137         [ +  + ]:            203 :     if (f.has_family())
    1138                 :                :     {
    1139         [ +  + ]:            181 :         write_start_element(xmlns, "family");
    1140         [ +  + ]:            543 :         write_attribute("val", f.family());
    1141         [ +  + ]:            362 :         write_end_element(xmlns, "family");
    1142                 :                :     }
    1143                 :                : 
    1144         [ +  + ]:            203 :     if (f.has_scheme())
    1145                 :                :     {
    1146         [ +  + ]:            182 :         write_start_element(xmlns, "scheme");
    1147   [ +  +  +  + ]:            546 :         write_attribute("val", f.scheme());
    1148         [ +  + ]:            364 :         write_end_element(xmlns, "scheme");
    1149                 :                :     }
    1150                 :                : 
    1151         [ +  + ]:            203 :     write_end_element(xmlns, "font");
    1152                 :            203 : }
    1153                 :                : 
    1154                 :            211 : void xlsx_producer::write_fill(const fill &f)
    1155                 :                : {
    1156   [ +  +  +  -  :            213 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    1157                 :                : 
    1158         [ +  + ]:            211 :     write_start_element(xmlns, "fill");
    1159                 :                : 
    1160         [ +  + ]:            211 :     if (f.type() == xlnt::fill_type::pattern)
    1161                 :                :     {
    1162            [ + ]:            210 :         const auto &pattern = f.pattern_fill();
    1163                 :                : 
    1164         [ +  + ]:            210 :         write_start_element(xmlns, "patternFill");
    1165                 :                : 
    1166      [ +  +  + ]:            420 :         write_attribute("patternType", pattern.type());
    1167                 :                : 
    1168      [ +  +  + ]:            210 :         if (pattern.foreground().is_set())
    1169                 :                :         {
    1170         [ +  + ]:            126 :             write_start_element(xmlns, "fgColor");
    1171      [ +  +  + ]:            126 :             write_color(pattern.foreground().get());
    1172         [ +  + ]:            252 :             write_end_element(xmlns, "fgColor");
    1173                 :                :         }
    1174                 :                : 
    1175      [ +  +  + ]:            210 :         if (pattern.background().is_set())
    1176                 :                :         {
    1177         [ +  + ]:            126 :             write_start_element(xmlns, "bgColor");
    1178      [ +  +  + ]:            126 :             write_color(pattern.background().get());
    1179         [ +  + ]:            252 :             write_end_element(xmlns, "bgColor");
    1180                 :                :         }
    1181                 :                : 
    1182         [ +  + ]:            210 :         write_end_element(xmlns, "patternFill");
    1183                 :            210 :     }
    1184         [ +  - ]:              1 :     else if (f.type() == xlnt::fill_type::gradient)
    1185                 :                :     {
    1186            [ + ]:              1 :         const auto &gradient = f.gradient_fill();
    1187                 :                : 
    1188         [ +  + ]:              1 :         write_start_element(xmlns, "gradientFill");
    1189      [ +  +  + ]:              2 :         write_attribute("gradientType", gradient.type());
    1190                 :                : 
    1191      [ +  -  + ]:              1 :         if (gradient.degree() != 0.)
    1192                 :                :         {
    1193      [ #  #  # ]:UBC           0 :             write_attribute<double>("degree", gradient.degree());
    1194                 :                :         }
    1195                 :                : 
    1196      [ +  -  + ]:CBC           1 :         if (gradient.left() != 0.)
    1197                 :                :         {
    1198      [ #  #  # ]:UBC           0 :             write_attribute<double>("left", gradient.left());
    1199                 :                :         }
    1200                 :                : 
    1201      [ +  -  + ]:CBC           1 :         if (gradient.right() != 0.)
    1202                 :                :         {
    1203      [ #  #  # ]:UBC           0 :             write_attribute<double>("right", gradient.right());
    1204                 :                :         }
    1205                 :                : 
    1206      [ +  -  + ]:CBC           1 :         if (gradient.top() != 0.)
    1207                 :                :         {
    1208      [ #  #  # ]:UBC           0 :             write_attribute<double>("top", gradient.top());
    1209                 :                :         }
    1210                 :                : 
    1211      [ +  -  + ]:CBC           1 :         if (gradient.bottom() != 0.)
    1212                 :                :         {
    1213      [ #  #  # ]:UBC           0 :             write_attribute<double>("bottom", gradient.bottom());
    1214                 :                :         }
    1215                 :                : 
    1216      [ +  -  + ]:CBC           1 :         for (const auto &stop : gradient.stops())
    1217                 :                :         {
    1218         [ #  # ]:UBC           0 :             write_start_element(xmlns, "stop");
    1219         [ #  # ]:              0 :             write_attribute<double>("position", stop.first);
    1220         [ #  # ]:              0 :             write_start_element(xmlns, "color");
    1221            [ # ]:              0 :             write_color(stop.second);
    1222         [ #  # ]:              0 :             write_end_element(xmlns, "color");
    1223         [ #  # ]:              0 :             write_end_element(xmlns, "stop");
    1224                 :CBC           1 :         }
    1225                 :                : 
    1226         [ +  + ]:              1 :         write_end_element(xmlns, "gradientFill");
    1227                 :              1 :     }
    1228                 :                : 
    1229         [ +  + ]:            211 :     write_end_element(xmlns, "fill");
    1230                 :            211 : }
    1231                 :                : 
    1232                 :             85 : void xlsx_producer::write_border(const border &current_border)
    1233                 :                : {
    1234   [ +  +  +  -  :             87 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    1235                 :                : 
    1236         [ +  + ]:             85 :     write_start_element(xmlns, "border");
    1237                 :                : 
    1238      [ +  -  + ]:             85 :     if (current_border.diagonal().is_set())
    1239                 :                :     {
    1240         [ #  # ]:UBC           0 :         auto up = current_border.diagonal().get() == diagonal_direction::both
    1241   [ #  #  #  #  :              0 :             || current_border.diagonal().get() == diagonal_direction::up;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1242      [ #  #  # ]:              0 :         write_attribute("diagonalUp", write_bool(up));
    1243                 :                : 
    1244         [ #  # ]:              0 :         auto down = current_border.diagonal().get() == diagonal_direction::both
    1245   [ #  #  #  #  :              0 :             || current_border.diagonal().get() == diagonal_direction::down;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1246      [ #  #  # ]:              0 :         write_attribute("diagonalDown", write_bool(down));
    1247                 :                :     }
    1248                 :                : 
    1249      [ +  +  + ]:CBC         680 :     for (const auto &side : xlnt::border::all_sides())
    1250                 :                :     {
    1251      [ +  +  + ]:            595 :         if (current_border.side(side).is_set())
    1252                 :                :         {
    1253         [ +  + ]:            420 :             const auto current_side = current_border.side(side).get();
    1254                 :                : 
    1255            [ + ]:            420 :             auto side_name = to_string(side);
    1256            [ + ]:            420 :             write_start_element(xmlns, side_name);
    1257                 :                : 
    1258      [ +  +  + ]:            420 :             if (current_side.style().is_set())
    1259                 :                :             {
    1260   [ +  +  +  + ]:            348 :                 write_attribute("style", current_side.style().get());
    1261                 :                :             }
    1262                 :                : 
    1263      [ +  +  + ]:            420 :             if (current_side.color().is_set())
    1264                 :                :             {
    1265         [ +  + ]:            116 :                 write_start_element(xmlns, "color");
    1266      [ +  +  + ]:            116 :                 write_color(current_side.color().get());
    1267         [ +  + ]:            232 :                 write_end_element(xmlns, "color");
    1268                 :                :             }
    1269                 :                : 
    1270            [ + ]:            420 :             write_end_element(xmlns, side_name);
    1271                 :            420 :         }
    1272                 :                :     }
    1273                 :                : 
    1274         [ +  + ]:             85 :     write_end_element(xmlns, "border");
    1275                 :             85 : }
    1276                 :                : 
    1277                 :             42 : void xlsx_producer::write_styles(const relationship & /*rel*/)
    1278                 :                : {
    1279   [ +  +  +  -  :             44 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    1280   [ +  +  +  -  :             44 :     static const auto &xmlns_mc = constants::ns("mc");
             +  +  -  - ]
    1281   [ +  +  +  -  :             44 :     static const auto &xmlns_x14 = constants::ns("x14");
             +  +  -  - ]
    1282   [ +  +  +  -  :             44 :     static const auto &xmlns_x14ac = constants::ns("x14ac");
             +  +  -  - ]
    1283                 :                : 
    1284         [ +  + ]:             84 :     write_start_element(xmlns, "styleSheet");
    1285         [ +  + ]:             42 :     write_namespace(xmlns, "");
    1286                 :                : 
    1287         [ +  + ]:             42 :     const auto &stylesheet = source_.impl().stylesheet_.get();
    1288                 :                : 
    1289                 :             42 :     auto using_namespace = [&stylesheet](const std::string &ns) {
    1290         [ +  - ]:             42 :         if (ns == "x14ac")
    1291                 :                :         {
    1292                 :             42 :             return stylesheet.known_fonts_enabled;
    1293                 :                :         }
    1294                 :                : 
    1295                 :UBC           0 :         return false;
    1296                 :CBC          42 :     };
    1297                 :                : 
    1298   [ +  +  +  + ]:             84 :     if (using_namespace("x14ac"))
    1299                 :                :     {
    1300         [ +  + ]:             48 :         write_namespace(xmlns_mc, "mc");
    1301         [ +  + ]:             48 :         write_namespace(xmlns_x14ac, "x14ac");
    1302      [ +  +  + ]:             48 :         write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
    1303                 :                :     }
    1304                 :                : 
    1305                 :                :     // Number Formats
    1306                 :                : 
    1307         [ +  + ]:             42 :     if (!stylesheet.number_formats.empty())
    1308                 :                :     {
    1309                 :             16 :         const auto &number_formats = stylesheet.number_formats;
    1310                 :                : 
    1311            [ + ]:             16 :         auto num_custom = std::count_if(number_formats.begin(), number_formats.end(),
    1312                 :             19 :             [](const number_format &nf) { return nf.id() >= 164; });
    1313                 :                : 
    1314         [ +  + ]:             16 :         if (num_custom > 0)
    1315                 :                :         {
    1316         [ +  + ]:              4 :             write_start_element(xmlns, "numFmts");
    1317         [ +  + ]:              2 :             write_attribute("count", num_custom);
    1318                 :                : 
    1319         [ +  + ]:              7 :             for (const auto &num_fmt : number_formats)
    1320                 :                :             {
    1321      [ +  +  + ]:              5 :                 if (num_fmt.id() < 164) continue;
    1322         [ +  + ]:              4 :                 write_start_element(xmlns, "numFmt");
    1323      [ +  +  + ]:              8 :                 write_attribute("numFmtId", num_fmt.id());
    1324      [ +  +  + ]:             12 :                 write_attribute("formatCode", num_fmt.format_string());
    1325         [ +  + ]:              8 :                 write_end_element(xmlns, "numFmt");
    1326                 :                :             }
    1327                 :                : 
    1328         [ +  + ]:              4 :             write_end_element(xmlns, "numFmts");
    1329                 :                :         }
    1330                 :                :     }
    1331                 :                : 
    1332                 :                :     // Fonts
    1333                 :                : 
    1334         [ +  - ]:             42 :     if (!stylesheet.fonts.empty())
    1335                 :                :     {
    1336                 :             42 :         const auto &fonts = stylesheet.fonts;
    1337                 :                : 
    1338         [ +  + ]:             42 :         write_start_element(xmlns, "fonts");
    1339         [ +  + ]:             84 :         write_attribute("count", fonts.size());
    1340                 :                : 
    1341         [ +  + ]:             42 :         if (stylesheet.known_fonts_enabled)
    1342                 :                :         {
    1343                 :            156 :             auto is_known_font = [](const font &f) {
    1344                 :                :                 const auto known_fonts = std::vector<font>{
    1345   [ +  +  +  +  :            780 :                     font().name("Calibri").family(2).size(12).color(theme_color(1)).scheme("minor")};
          +  +  +  +  +  
             +  +  +  -  
                      - ]
    1346                 :                : 
    1347            [ + ]:            312 :                 return std::find(known_fonts.begin(), known_fonts.end(), f) != known_fonts.end();
    1348   [ +  +  -  -  :            468 :             };
                   -  - ]
    1349                 :                : 
    1350                 :             24 :             std::size_t num_known_fonts = 0;
    1351                 :                : 
    1352         [ +  + ]:            180 :             for (const auto &current_font : fonts)
    1353                 :                :             {
    1354      [ +  +  + ]:            156 :                 if (is_known_font(current_font))
    1355                 :                :                 {
    1356                 :             24 :                     num_known_fonts += 1;
    1357                 :                :                 }
    1358                 :                :             }
    1359                 :                : 
    1360      [ +  +  + ]:             48 :             write_attribute(xml::qname(xmlns_x14ac, "knownFonts"), num_known_fonts);
    1361                 :                :         }
    1362                 :                : 
    1363         [ +  + ]:            245 :         for (const auto &current_font : fonts)
    1364                 :                :         {
    1365            [ + ]:            203 :             write_font(current_font);
    1366                 :                :         }
    1367                 :                : 
    1368         [ +  + ]:             84 :         write_end_element(xmlns, "fonts");
    1369                 :                :     }
    1370                 :                : 
    1371                 :                :     // Fills
    1372                 :                : 
    1373         [ +  - ]:             42 :     if (!stylesheet.fills.empty())
    1374                 :                :     {
    1375                 :             42 :         const auto &fills = stylesheet.fills;
    1376                 :                : 
    1377         [ +  + ]:             42 :         write_start_element(xmlns, "fills");
    1378         [ +  + ]:             84 :         write_attribute("count", fills.size());
    1379                 :                : 
    1380         [ +  + ]:            253 :         for (auto &current_fill : fills)
    1381                 :                :         {
    1382            [ + ]:            211 :             write_fill(current_fill);
    1383                 :                :         }
    1384                 :                : 
    1385         [ +  + ]:             84 :         write_end_element(xmlns, "fills");
    1386                 :                :     }
    1387                 :                : 
    1388                 :                :     // Borders
    1389                 :                : 
    1390         [ +  - ]:             42 :     if (!stylesheet.borders.empty())
    1391                 :                :     {
    1392                 :             42 :         const auto &borders = stylesheet.borders;
    1393                 :                : 
    1394         [ +  + ]:             42 :         write_start_element(xmlns, "borders");
    1395         [ +  + ]:             84 :         write_attribute("count", borders.size());
    1396                 :                : 
    1397         [ +  + ]:            127 :         for (const auto &current_border : borders)
    1398                 :                :         {
    1399            [ + ]:             85 :             write_border(current_border);
    1400                 :                :         }
    1401                 :                : 
    1402         [ +  + ]:             84 :         write_end_element(xmlns, "borders");
    1403                 :                :     }
    1404                 :                : 
    1405                 :                :     // Style XFs
    1406         [ +  - ]:             42 :     if (stylesheet.style_impls.size() > 0)
    1407                 :                :     {
    1408         [ +  + ]:             42 :         write_start_element(xmlns, "cellStyleXfs");
    1409         [ +  + ]:             84 :         write_attribute("count", stylesheet.style_impls.size());
    1410                 :                : 
    1411         [ +  + ]:            258 :         for (const auto &current_style_name : stylesheet.style_names)
    1412                 :                :         {
    1413            [ + ]:            216 :             const auto &current_style_impl = stylesheet.style_impls.at(current_style_name);
    1414                 :                : 
    1415         [ +  + ]:            216 :             write_start_element(xmlns, "xf");
    1416                 :                : 
    1417         [ +  - ]:            216 :             if (current_style_impl.number_format_id.is_set())
    1418                 :                :             {
    1419      [ +  +  + ]:            648 :                 write_attribute("numFmtId", current_style_impl.number_format_id.get());
    1420                 :                :             }
    1421                 :                : 
    1422         [ +  - ]:            216 :             if (current_style_impl.font_id.is_set())
    1423                 :                :             {
    1424      [ +  +  + ]:            648 :                 write_attribute("fontId", current_style_impl.font_id.get());
    1425                 :                :             }
    1426                 :                : 
    1427         [ +  + ]:            216 :             if (current_style_impl.fill_id.is_set())
    1428                 :                :             {
    1429      [ +  +  + ]:            645 :                 write_attribute("fillId", current_style_impl.fill_id.get());
    1430                 :                :             }
    1431                 :                : 
    1432         [ +  + ]:            216 :             if (current_style_impl.border_id.is_set())
    1433                 :                :             {
    1434      [ +  +  + ]:            645 :                 write_attribute("borderId", current_style_impl.border_id.get());
    1435                 :                :             }
    1436                 :                : 
    1437                 :            216 :             if (current_style_impl.number_format_id.is_set()
    1438   [ +  -  +  +  :            216 :                 && current_style_impl.number_format_applied.is_set())
                   +  + ]
    1439                 :                :             {
    1440         [ +  + ]:            170 :                 write_attribute("applyNumberFormat",
    1441         [ +  + ]:            340 :                     write_bool(current_style_impl.number_format_applied.get()));
    1442                 :                :             }
    1443                 :                : 
    1444                 :            216 :             if (current_style_impl.fill_id.is_set()
    1445   [ +  +  +  +  :            216 :                 && current_style_impl.fill_applied.is_set())
                   +  + ]
    1446                 :                :             {
    1447         [ +  + ]:             41 :                 write_attribute("applyFill",
    1448         [ +  + ]:             82 :                     write_bool(current_style_impl.fill_applied.get()));
    1449                 :                :             }
    1450                 :                : 
    1451                 :            216 :             if (current_style_impl.font_id.is_set()
    1452   [ +  -  +  +  :            216 :                 && current_style_impl.font_applied.is_set())
                   +  + ]
    1453                 :                :             {
    1454         [ +  + ]:             12 :                 write_attribute("applyFont",
    1455         [ +  + ]:             24 :                     write_bool(current_style_impl.font_applied.get()));
    1456                 :                :             }
    1457                 :                : 
    1458                 :            216 :             if (current_style_impl.border_id.is_set()
    1459   [ +  +  +  +  :            216 :                 && current_style_impl.border_applied.is_set())
                   +  + ]
    1460                 :                :             {
    1461         [ +  + ]:            135 :                 write_attribute("applyBorder",
    1462         [ +  + ]:            270 :                     write_bool(current_style_impl.border_applied.get()));
    1463                 :                :             }
    1464                 :                : 
    1465                 :            216 :             if (current_style_impl.alignment_id.is_set()
    1466   [ +  +  +  +  :            216 :                 && current_style_impl.alignment_applied.is_set())
                   +  + ]
    1467                 :                :             {
    1468         [ +  + ]:             43 :                 write_attribute("applyAlignment",
    1469         [ +  + ]:             86 :                     write_bool(current_style_impl.alignment_applied.get()));
    1470                 :                :             }
    1471                 :                : 
    1472                 :            216 :             if (current_style_impl.protection_id.is_set()
    1473   [ -  +  -  -  :            216 :                 && current_style_impl.protection_applied.is_set())
                   -  + ]
    1474                 :                :             {
    1475         [ #  # ]:UBC           0 :                 write_attribute("applyProtection",
    1476         [ #  # ]:              0 :                     write_bool(current_style_impl.protection_applied.get()));
    1477                 :                :             }
    1478                 :                : 
    1479         [ -  + ]:CBC         216 :             if (current_style_impl.pivot_button_)
    1480                 :                :             {
    1481      [ #  #  # ]:UBC           0 :                 write_attribute("pivotButton", write_bool(true));
    1482                 :                :             }
    1483                 :                : 
    1484         [ -  + ]:CBC         216 :             if (current_style_impl.quote_prefix_)
    1485                 :                :             {
    1486      [ #  #  # ]:UBC           0 :                 write_attribute("quotePrefix", write_bool(true));
    1487                 :                :             }
    1488                 :                : 
    1489         [ +  + ]:CBC         216 :             if (current_style_impl.alignment_id.is_set())
    1490                 :                :             {
    1491            [ + ]:             45 :                 const auto &current_alignment = stylesheet.alignments[current_style_impl.alignment_id.get()];
    1492                 :                : 
    1493         [ +  + ]:             45 :                 write_start_element(xmlns, "alignment");
    1494                 :                : 
    1495      [ +  +  - ]:             45 :                 if (current_alignment.vertical().is_set())
    1496                 :                :                 {
    1497   [ +  +  +  + ]:            135 :                     write_attribute("vertical", current_alignment.vertical().get());
    1498                 :                :                 }
    1499                 :                : 
    1500      [ +  +  + ]:             45 :                 if (current_alignment.horizontal().is_set())
    1501                 :                :                 {
    1502   [ +  +  +  + ]:              3 :                     write_attribute("horizontal", current_alignment.horizontal().get());
    1503                 :                :                 }
    1504                 :                : 
    1505      [ +  +  + ]:             45 :                 if (current_alignment.rotation().is_set())
    1506                 :                :                 {
    1507   [ +  +  +  + ]:              3 :                     write_attribute("textRotation", current_alignment.rotation().get());
    1508                 :                :                 }
    1509                 :                : 
    1510      [ +  +  + ]:             45 :                 if (current_alignment.wrap())
    1511                 :                :                 {
    1512   [ +  +  +  + ]:              3 :                     write_attribute("wrapText", write_bool(current_alignment.wrap()));
    1513                 :                :                 }
    1514                 :                : 
    1515      [ +  +  + ]:             45 :                 if (current_alignment.indent().is_set())
    1516                 :                :                 {
    1517   [ +  +  +  + ]:              3 :                     write_attribute("indent", current_alignment.indent().get());
    1518                 :                :                 }
    1519                 :                : 
    1520      [ +  -  + ]:             45 :                 if (current_alignment.shrink())
    1521                 :                :                 {
    1522   [ #  #  #  # ]:UBC           0 :                     write_attribute("shrinkToFit", write_bool(current_alignment.shrink()));
    1523                 :                :                 }
    1524                 :                : 
    1525         [ +  + ]:CBC          90 :                 write_end_element(xmlns, "alignment");
    1526                 :                :             }
    1527                 :                : 
    1528         [ -  + ]:            216 :             if (current_style_impl.protection_id.is_set())
    1529                 :                :             {
    1530            [ # ]:UBC           0 :                 const auto &current_protection = stylesheet.protections[current_style_impl.protection_id.get()];
    1531                 :                : 
    1532         [ #  # ]:              0 :                 write_start_element(xmlns, "protection");
    1533   [ #  #  #  # ]:              0 :                 write_attribute("locked", write_bool(current_protection.locked()));
    1534   [ #  #  #  # ]:              0 :                 write_attribute("hidden", write_bool(current_protection.hidden()));
    1535         [ #  # ]:              0 :                 write_end_element(xmlns, "protection");
    1536                 :                :             }
    1537                 :                : 
    1538         [ +  + ]:CBC         432 :             write_end_element(xmlns, "xf");
    1539                 :                :         }
    1540                 :                : 
    1541         [ +  + ]:             84 :         write_end_element(xmlns, "cellStyleXfs");
    1542                 :                :     }
    1543                 :                : 
    1544                 :                :     // Format XFs
    1545                 :                : 
    1546         [ +  + ]:             42 :     write_start_element(xmlns, "cellXfs");
    1547         [ +  + ]:             84 :     write_attribute("count", stylesheet.format_impls.size());
    1548                 :                : 
    1549         [ +  + ]:            225 :     for (auto &current_format_item : stylesheet.format_impls)
    1550                 :                :     {
    1551                 :            183 :         auto &current_format_impl = *current_format_item;
    1552                 :                : 
    1553         [ +  + ]:            183 :         write_start_element(xmlns, "xf");
    1554                 :                : 
    1555         [ +  + ]:            183 :         if (current_format_impl.number_format_id.is_set())
    1556                 :                :         {
    1557      [ +  +  + ]:            531 :             write_attribute("numFmtId", current_format_impl.number_format_id.get());
    1558                 :                :         }
    1559                 :                : 
    1560         [ +  + ]:            183 :         if (current_format_impl.font_id.is_set())
    1561                 :                :         {
    1562      [ +  +  + ]:            534 :             write_attribute("fontId", current_format_impl.font_id.get());
    1563                 :                :         }
    1564                 :                : 
    1565         [ +  + ]:            183 :         if (current_format_impl.fill_id.is_set())
    1566                 :                :         {
    1567      [ +  +  + ]:            501 :             write_attribute("fillId", current_format_impl.fill_id.get());
    1568                 :                :         }
    1569                 :                : 
    1570         [ +  + ]:            183 :         if (current_format_impl.border_id.is_set())
    1571                 :                :         {
    1572      [ +  +  + ]:            510 :             write_attribute("borderId", current_format_impl.border_id.get());
    1573                 :                :         }
    1574                 :                : 
    1575         [ +  + ]:            183 :         if (current_format_impl.style.is_set())
    1576                 :                :         {
    1577   [ +  +  +  + ]:            531 :             write_attribute("xfId", stylesheet.style_index(current_format_impl.style.get()));
    1578                 :                :         }
    1579                 :                : 
    1580                 :            183 :         if (current_format_impl.number_format_id.is_set()
    1581   [ +  +  +  +  :            183 :             && current_format_impl.number_format_applied.is_set())
                   +  + ]
    1582                 :                :         {
    1583         [ +  + ]:             15 :             write_attribute("applyNumberFormat",
    1584         [ +  + ]:             30 :                 write_bool(current_format_impl.number_format_applied.get()));
    1585                 :                :         }
    1586                 :                : 
    1587                 :            183 :         if (current_format_impl.fill_id.is_set()
    1588   [ +  +  +  +  :            183 :             && current_format_impl.fill_applied.is_set())
                   +  + ]
    1589                 :                :         {
    1590         [ +  + ]:              5 :             write_attribute("applyFill",
    1591         [ +  + ]:             10 :                 write_bool(current_format_impl.fill_applied.get()));
    1592                 :                :         }
    1593                 :                : 
    1594                 :            183 :         if (current_format_impl.font_id.is_set()
    1595   [ +  +  +  +  :            183 :             && current_format_impl.font_applied.is_set())
                   +  + ]
    1596                 :                :         {
    1597         [ +  + ]:             91 :             write_attribute("applyFont",
    1598         [ +  + ]:            182 :                 write_bool(current_format_impl.font_applied.get()));
    1599                 :                :         }
    1600                 :                : 
    1601                 :            183 :         if (current_format_impl.border_id.is_set()
    1602   [ +  +  +  +  :            183 :             && current_format_impl.border_applied.is_set())
                   +  + ]
    1603                 :                :         {
    1604         [ +  + ]:              9 :             write_attribute("applyBorder",
    1605         [ +  + ]:             18 :                 write_bool(current_format_impl.border_applied.get()));
    1606                 :                :         }
    1607                 :                : 
    1608         [ +  + ]:            183 :         if (current_format_impl.alignment_applied.is_set())
    1609                 :                :         {
    1610         [ +  + ]:             58 :             write_attribute("applyAlignment",
    1611         [ +  + ]:            116 :                 write_bool(current_format_impl.alignment_applied.get()));
    1612                 :                :         }
    1613                 :                : 
    1614         [ +  + ]:            183 :         if (current_format_impl.protection_applied.is_set())
    1615                 :                :         {
    1616         [ +  + ]:             12 :             write_attribute("applyProtection",
    1617         [ +  + ]:             24 :                 write_bool(current_format_impl.protection_applied.get()));
    1618                 :                :         }
    1619                 :                : 
    1620         [ -  + ]:            183 :         if (current_format_impl.pivot_button_)
    1621                 :                :         {
    1622      [ #  #  # ]:UBC           0 :             write_attribute("pivotButton", write_bool(true));
    1623                 :                :         }
    1624                 :                : 
    1625         [ -  + ]:CBC         183 :         if (current_format_impl.quote_prefix_)
    1626                 :                :         {
    1627      [ #  #  # ]:UBC           0 :             write_attribute("quotePrefix", write_bool(true));
    1628                 :                :         }
    1629                 :                : 
    1630         [ +  + ]:CBC         183 :         if (current_format_impl.alignment_id.is_set())
    1631                 :                :         {
    1632            [ + ]:             58 :             const auto &current_alignment = stylesheet.alignments[current_format_impl.alignment_id.get()];
    1633                 :                : 
    1634         [ +  + ]:             58 :             write_start_element(xmlns, "alignment");
    1635                 :                : 
    1636      [ +  +  + ]:             58 :             if (current_alignment.horizontal().is_set())
    1637                 :                :             {
    1638   [ +  +  +  + ]:             69 :                 write_attribute("horizontal", current_alignment.horizontal().get());
    1639                 :                :             }
    1640                 :                : 
    1641      [ +  +  + ]:             58 :             if (current_alignment.vertical().is_set())
    1642                 :                :             {
    1643   [ +  +  +  + ]:             87 :                 write_attribute("vertical", current_alignment.vertical().get());
    1644                 :                :             }
    1645                 :                : 
    1646      [ +  +  + ]:             58 :             if (current_alignment.rotation().is_set())
    1647                 :                :             {
    1648   [ +  +  +  + ]:             15 :                 write_attribute("textRotation", current_alignment.rotation().get());
    1649                 :                :             }
    1650                 :                : 
    1651      [ +  +  + ]:             58 :             if (current_alignment.wrap())
    1652                 :                :             {
    1653   [ +  +  +  + ]:             54 :                 write_attribute("wrapText", write_bool(current_alignment.wrap()));
    1654                 :                :             }
    1655                 :                : 
    1656      [ +  +  + ]:             58 :             if (current_alignment.indent().is_set())
    1657                 :                :             {
    1658   [ +  +  +  + ]:             27 :                 write_attribute("indent", current_alignment.indent().get());
    1659                 :                :             }
    1660                 :                : 
    1661      [ +  +  + ]:             58 :             if (current_alignment.shrink())
    1662                 :                :             {
    1663   [ +  +  +  + ]:             24 :                 write_attribute("shrinkToFit", write_bool(current_alignment.shrink()));
    1664                 :                :             }
    1665                 :                : 
    1666         [ +  + ]:            116 :             write_end_element(xmlns, "alignment");
    1667                 :                :         }
    1668                 :                : 
    1669         [ +  + ]:            183 :         if (current_format_impl.protection_id.is_set())
    1670                 :                :         {
    1671            [ + ]:              1 :             const auto &current_protection = stylesheet.protections[current_format_impl.protection_id.get()];
    1672                 :                : 
    1673         [ +  + ]:              1 :             write_start_element(xmlns, "protection");
    1674   [ +  +  +  + ]:              3 :             write_attribute("locked", write_bool(current_protection.locked()));
    1675   [ +  +  +  + ]:              3 :             write_attribute("hidden", write_bool(current_protection.hidden()));
    1676         [ +  + ]:              2 :             write_end_element(xmlns, "protection");
    1677                 :                :         }
    1678                 :                : 
    1679         [ +  + ]:            366 :         write_end_element(xmlns, "xf");
    1680                 :                :     }
    1681                 :                : 
    1682         [ +  + ]:             42 :     write_end_element(xmlns, "cellXfs");
    1683                 :                : 
    1684                 :                :     // Styles
    1685         [ +  - ]:             42 :     if (stylesheet.style_impls.size() > 0)
    1686                 :                :     {
    1687         [ +  + ]:             42 :         write_start_element(xmlns, "cellStyles");
    1688         [ +  + ]:             84 :         write_attribute("count", stylesheet.style_impls.size());
    1689                 :             42 :         std::size_t style_index = 0;
    1690                 :                : 
    1691         [ +  + ]:            258 :         for (auto &current_style_name : stylesheet.style_names)
    1692                 :                :         {
    1693            [ + ]:            216 :             const auto &current_style = stylesheet.style_impls.at(current_style_name);
    1694                 :                : 
    1695         [ +  + ]:            216 :             write_start_element(xmlns, "cellStyle");
    1696                 :                : 
    1697      [ +  +  + ]:            648 :             write_attribute("name", current_style.name);
    1698         [ +  + ]:            432 :             write_attribute("xfId", style_index++);
    1699                 :                : 
    1700         [ +  - ]:            216 :             if (current_style.builtin_id.is_set())
    1701                 :                :             {
    1702      [ +  +  + ]:            648 :                 write_attribute("builtinId", current_style.builtin_id.get());
    1703                 :                :             }
    1704                 :                : 
    1705         [ -  + ]:            216 :             if (current_style.hidden_style)
    1706                 :                :             {
    1707      [ #  #  # ]:UBC           0 :                 write_attribute("hidden", write_bool(true));
    1708                 :                :             }
    1709                 :                : 
    1710   [ +  -  +  +  :CBC         216 :             if (current_style.builtin_id.is_set() && current_style.custom_builtin)
                   +  + ]
    1711                 :                :             {
    1712      [ +  +  + ]:            492 :                 write_attribute("customBuiltin", write_bool(current_style.custom_builtin));
    1713                 :                :             }
    1714                 :                : 
    1715         [ +  + ]:            432 :             write_end_element(xmlns, "cellStyle");
    1716                 :                :         }
    1717                 :                : 
    1718         [ +  + ]:             84 :         write_end_element(xmlns, "cellStyles");
    1719                 :                :     }
    1720                 :                : 
    1721                 :                :     // Conditional Formats
    1722         [ +  + ]:             42 :     write_start_element(xmlns, "dxfs");
    1723         [ +  + ]:             84 :     write_attribute("count", stylesheet.conditional_format_impls.size());
    1724                 :                : 
    1725         [ -  + ]:             42 :     for (auto &rule : stylesheet.conditional_format_impls)
    1726                 :                :     {
    1727         [ #  # ]:UBC           0 :         write_start_element(xmlns, "dxf");
    1728                 :                : 
    1729         [ #  # ]:              0 :         if (rule.border_id.is_set())
    1730                 :                :         {
    1731         [ #  # ]:              0 :             const auto &current_border = stylesheet.borders.at(rule.border_id.get());
    1732            [ # ]:              0 :             write_border(current_border);
    1733                 :                :         }
    1734                 :                : 
    1735         [ #  # ]:              0 :         if (rule.fill_id.is_set())
    1736                 :                :         {
    1737         [ #  # ]:              0 :             const auto &current_fill = stylesheet.fills.at(rule.fill_id.get());
    1738            [ # ]:              0 :             write_fill(current_fill);
    1739                 :                :         }
    1740                 :                : 
    1741         [ #  # ]:              0 :         if (rule.font_id.is_set())
    1742                 :                :         {
    1743         [ #  # ]:              0 :             const auto &current_font = stylesheet.fonts.at(rule.font_id.get());
    1744            [ # ]:              0 :             write_font(current_font);
    1745                 :                :         }
    1746                 :                : 
    1747         [ #  # ]:              0 :         write_end_element(xmlns, "dxf");
    1748                 :                :     }
    1749                 :                : 
    1750         [ +  + ]:CBC          84 :     write_end_element(xmlns, "dxfs");
    1751                 :                : 
    1752         [ +  + ]:             84 :     write_start_element(xmlns, "tableStyles");
    1753         [ +  + ]:             84 :     write_attribute("count", "0");
    1754         [ +  + ]:             84 :     write_attribute("defaultTableStyle", "TableStyleMedium9");
    1755         [ +  + ]:             84 :     write_attribute("defaultPivotStyle", "PivotStyleMedium7");
    1756         [ +  + ]:             42 :     write_end_element(xmlns, "tableStyles");
    1757                 :                : 
    1758         [ +  + ]:             42 :     if (!stylesheet.colors.empty())
    1759                 :                :     {
    1760         [ +  + ]:              2 :         write_start_element(xmlns, "colors");
    1761         [ +  + ]:              1 :         write_start_element(xmlns, "indexedColors");
    1762                 :                : 
    1763         [ +  + ]:             14 :         for (auto &c : stylesheet.colors)
    1764                 :                :         {
    1765         [ +  + ]:             13 :             write_start_element(xmlns, "rgbColor");
    1766   [ +  +  +  + ]:             39 :             write_attribute("rgb", c.rgb().hex_string());
    1767         [ +  + ]:             26 :             write_end_element(xmlns, "rgbColor");
    1768                 :                :         }
    1769                 :                : 
    1770         [ +  + ]:              2 :         write_end_element(xmlns, "indexedColors");
    1771         [ +  + ]:              2 :         write_end_element(xmlns, "colors");
    1772                 :                :     }
    1773                 :                : 
    1774                 :             42 :     auto using_extensions = stylesheet.default_slicer_style.is_set();
    1775                 :                : 
    1776         [ +  + ]:             42 :     if (using_extensions)
    1777                 :                :     {
    1778         [ +  + ]:             26 :         write_start_element(xmlns, "extLst");
    1779                 :                : 
    1780         [ +  - ]:             26 :         if (stylesheet.default_slicer_style.is_set())
    1781                 :                :         {
    1782         [ +  + ]:             52 :             write_start_element(xmlns, "ext");
    1783         [ +  + ]:             52 :             write_namespace(xmlns_x14, "x14");
    1784         [ +  + ]:             52 :             write_attribute("uri", "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"); // slicerStyles URI
    1785         [ +  + ]:             26 :             write_start_element(xmlns_x14, "slicerStyles");
    1786   [ +  +  +  + ]:             78 :             write_attribute("defaultSlicerStyle", stylesheet.default_slicer_style.get());
    1787         [ +  + ]:             52 :             write_end_element(xmlns_x14, "slicerStyles");
    1788         [ +  + ]:             52 :             write_end_element(xmlns, "ext");
    1789                 :                :         }
    1790                 :                : 
    1791         [ +  + ]:             52 :         write_end_element(xmlns, "extLst");
    1792                 :                :     }
    1793                 :                : 
    1794         [ +  + ]:             42 :     write_end_element(xmlns, "styleSheet");
    1795                 :             42 : }
    1796                 :                : 
    1797                 :             41 : void xlsx_producer::write_theme(const relationship &theme_rel)
    1798                 :                : {
    1799   [ +  +  +  -  :             43 :     static const auto &xmlns_a = constants::ns("drawingml");
             +  +  -  - ]
    1800   [ +  +  +  -  :             43 :     static const auto &xmlns_thm15 = constants::ns("thm15");
             +  +  -  - ]
    1801                 :                : 
    1802         [ +  + ]:             82 :     write_start_element(xmlns_a, "theme");
    1803         [ +  + ]:             82 :     write_namespace(xmlns_a, "a");
    1804         [ +  + ]:             82 :     write_attribute("name", "Office Theme");
    1805                 :                : 
    1806         [ +  + ]:             82 :     write_start_element(xmlns_a, "themeElements");
    1807         [ +  + ]:             82 :     write_start_element(xmlns_a, "clrScheme");
    1808         [ +  + ]:             41 :     write_attribute("name", "Office");
    1809                 :                : 
    1810                 :                :     struct scheme_element
    1811                 :                :     {
    1812                 :                :         std::string name;
    1813                 :                :         std::string sub_element_name;
    1814                 :                :         std::string val;
    1815                 :                :     };
    1816                 :                : 
    1817                 :                :     std::vector<scheme_element> scheme_elements = {
    1818                 :UBC           0 :         {"dk1", "sysClr", "windowText"},
    1819                 :                :         {"lt1", "sysClr", "window"},
    1820                 :                :         {"dk2", "srgbClr", "44546A"},
    1821                 :                :         {"lt2", "srgbClr", "E7E6E6"},
    1822                 :                :         {"accent1", "srgbClr", "5B9BD5"},
    1823                 :                :         {"accent2", "srgbClr", "ED7D31"},
    1824                 :                :         {"accent3", "srgbClr", "A5A5A5"},
    1825                 :                :         {"accent4", "srgbClr", "FFC000"},
    1826                 :                :         {"accent5", "srgbClr", "4472C4"},
    1827                 :                :         {"accent6", "srgbClr", "70AD47"},
    1828                 :                :         {"hlink", "srgbClr", "0563C1"},
    1829                 :                :         {"folHlink", "srgbClr", "954F72"},
    1830   [ +  +  +  -  :CBC         574 :     };
                      - ]
    1831                 :                : 
    1832      [ +  +  + ]:            533 :     for (auto element : scheme_elements)
    1833                 :                :     {
    1834            [ + ]:            492 :         write_start_element(xmlns_a, element.name);
    1835            [ + ]:            492 :         write_start_element(xmlns_a, element.sub_element_name);
    1836      [ +  +  + ]:           1476 :         write_attribute("val", element.val);
    1837                 :                : 
    1838      [ +  +  + ]:            492 :         if (element.name == "dk1")
    1839                 :                :         {
    1840         [ +  + ]:             82 :             write_attribute("lastClr", "000000");
    1841                 :                :         }
    1842      [ +  +  + ]:            451 :         else if (element.name == "lt1")
    1843                 :                :         {
    1844         [ +  + ]:             82 :             write_attribute("lastClr", "FFFFFF");
    1845                 :                :         }
    1846                 :                : 
    1847            [ + ]:            492 :         write_end_element(xmlns_a, element.sub_element_name);
    1848            [ + ]:            492 :         write_end_element(xmlns_a, element.name);
    1849                 :            492 :     }
    1850                 :                : 
    1851         [ +  + ]:             41 :     write_end_element(xmlns_a, "clrScheme");
    1852                 :                : 
    1853                 :                :     struct font_scheme
    1854                 :                :     {
    1855                 :                :         bool typeface;
    1856                 :                :         std::string script;
    1857                 :                :         std::string major;
    1858                 :                :         std::string minor;
    1859                 :                :     };
    1860                 :                : 
    1861                 :UBC           0 :     static const auto font_schemes = std::vector<font_scheme>{{true, "latin", "Calibri Light", "Calibri"},
    1862                 :                :         {true, "ea", "", ""}, {true, "cs", "", ""}, {false, "Jpan", "Yu Gothic Light", "Yu Gothic"},
    1863                 :                :         {false, "Hang", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95",
    1864                 :                :             "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95"},
    1865                 :                :         {false, "Hans", "DengXian Light", "DengXian"},
    1866                 :                :         {false, "Hant", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94",
    1867                 :                :             "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94"},
    1868                 :                :         {false, "Arab", "Times New Roman", "Arial"}, {false, "Hebr", "Times New Roman", "Arial"},
    1869                 :                :         {false, "Thai", "Tahoma", "Tahoma"}, {false, "Ethi", "Nyala", "Nyala"}, {false, "Beng", "Vrinda", "Vrinda"},
    1870                 :                :         {false, "Gujr", "Shruti", "Shruti"}, {false, "Khmr", "MoolBoran", "DaunPenh"},
    1871                 :                :         {false, "Knda", "Tunga", "Tunga"}, {false, "Guru", "Raavi", "Raavi"}, {false, "Cans", "Euphemia", "Euphemia"},
    1872                 :                :         {false, "Cher", "Plantagenet Cherokee", "Plantagenet Cherokee"},
    1873                 :                :         {false, "Yiii", "Microsoft Yi Baiti", "Microsoft Yi Baiti"},
    1874                 :                :         {false, "Tibt", "Microsoft Himalaya", "Microsoft Himalaya"}, {false, "Thaa", "MV Boli", "MV Boli"},
    1875                 :                :         {false, "Deva", "Mangal", "Mangal"}, {false, "Telu", "Gautami", "Gautami"}, {false, "Taml", "Latha", "Latha"},
    1876                 :                :         {false, "Syrc", "Estrangelo Edessa", "Estrangelo Edessa"}, {false, "Orya", "Kalinga", "Kalinga"},
    1877                 :                :         {false, "Mlym", "Kartika", "Kartika"}, {false, "Laoo", "DokChampa", "DokChampa"},
    1878                 :                :         {false, "Sinh", "Iskoola Pota", "Iskoola Pota"}, {false, "Mong", "Mongolian Baiti", "Mongolian Baiti"},
    1879                 :                :         {false, "Viet", "Times New Roman", "Arial"}, {false, "Uigh", "Microsoft Uighur", "Microsoft Uighur"},
    1880   [ +  +  +  -  :CBC          77 :         {false, "Geor", "Sylfaen", "Sylfaen"}};
          +  +  +  -  -  
                   -  - ]
    1881                 :                : 
    1882         [ +  + ]:             82 :     write_start_element(xmlns_a, "fontScheme");
    1883         [ +  + ]:             41 :     write_attribute("name", "Office");
    1884                 :                : 
    1885         [ +  + ]:            123 :     for (auto major : {true, false})
    1886                 :                :     {
    1887   [ +  +  +  + ]:             82 :         write_start_element(xmlns_a, major ? "majorFont" : "minorFont");
    1888                 :                : 
    1889         [ +  + ]:           2788 :         for (const auto &scheme : font_schemes)
    1890                 :                :         {
    1891      [ +  +  + ]:           2706 :             const auto scheme_value = major ? scheme.major : scheme.minor;
    1892                 :                : 
    1893         [ +  + ]:           2706 :             if (scheme.typeface)
    1894                 :                :             {
    1895            [ + ]:            246 :                 write_start_element(xmlns_a, scheme.script);
    1896      [ +  +  + ]:            738 :                 write_attribute("typeface", scheme_value);
    1897                 :                : 
    1898      [ +  +  + ]:            246 :                 if (scheme_value == "Calibri Light")
    1899                 :                :                 {
    1900         [ +  + ]:             82 :                     write_attribute("panose", "020F0302020204030204");
    1901                 :                :                 }
    1902      [ +  +  + ]:            205 :                 else if (scheme_value == "Calibri")
    1903                 :                :                 {
    1904         [ +  + ]:             82 :                     write_attribute("panose", "020F0502020204030204");
    1905                 :                :                 }
    1906                 :                : 
    1907            [ + ]:            246 :                 write_end_element(xmlns_a, scheme.script);
    1908                 :                :             }
    1909                 :                :             else
    1910                 :                :             {
    1911         [ +  + ]:           2460 :                 write_start_element(xmlns_a, "font");
    1912      [ +  +  + ]:           7380 :                 write_attribute("script", scheme.script);
    1913      [ +  +  + ]:           7380 :                 write_attribute("typeface", scheme_value);
    1914         [ +  + ]:           4920 :                 write_end_element(xmlns_a, "font");
    1915                 :                :             }
    1916                 :           2706 :         }
    1917                 :                : 
    1918   [ +  +  +  + ]:            164 :         write_end_element(xmlns_a, major ? "majorFont" : "minorFont");
    1919                 :                :     }
    1920                 :                : 
    1921         [ +  + ]:             82 :     write_end_element(xmlns_a, "fontScheme");
    1922                 :                : 
    1923         [ +  + ]:             82 :     write_start_element(xmlns_a, "fmtScheme");
    1924         [ +  + ]:             82 :     write_attribute("name", "Office");
    1925                 :                : 
    1926         [ +  + ]:             82 :     write_start_element(xmlns_a, "fillStyleLst");
    1927         [ +  + ]:             82 :     write_start_element(xmlns_a, "solidFill");
    1928         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    1929         [ +  + ]:             82 :     write_attribute("val", "phClr");
    1930         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    1931         [ +  + ]:             82 :     write_end_element(xmlns_a, "solidFill");
    1932                 :                : 
    1933         [ +  + ]:             82 :     write_start_element(xmlns_a, "gradFill");
    1934         [ +  + ]:             82 :     write_attribute("rotWithShape", "1");
    1935         [ +  + ]:             82 :     write_start_element(xmlns_a, "gsLst");
    1936                 :                : 
    1937         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    1938         [ +  + ]:             82 :     write_attribute("pos", "0");
    1939         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    1940         [ +  + ]:             82 :     write_attribute("val", "phClr");
    1941         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    1942         [ +  + ]:             82 :     write_attribute("val", "110000");
    1943         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    1944         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    1945         [ +  + ]:             82 :     write_attribute("val", "105000");
    1946         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    1947         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    1948         [ +  + ]:             82 :     write_attribute("val", "67000");
    1949         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    1950         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    1951         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    1952                 :                : 
    1953         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    1954         [ +  + ]:             82 :     write_attribute("pos", "50000");
    1955         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    1956         [ +  + ]:             82 :     write_attribute("val", "phClr");
    1957         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    1958         [ +  + ]:             82 :     write_attribute("val", "105000");
    1959         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    1960         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    1961         [ +  + ]:             82 :     write_attribute("val", "103000");
    1962         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    1963         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    1964         [ +  + ]:             82 :     write_attribute("val", "73000");
    1965         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    1966         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    1967         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    1968                 :                : 
    1969         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    1970         [ +  + ]:             82 :     write_attribute("pos", "100000");
    1971         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    1972         [ +  + ]:             82 :     write_attribute("val", "phClr");
    1973         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    1974         [ +  + ]:             82 :     write_attribute("val", "105000");
    1975         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    1976         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    1977         [ +  + ]:             82 :     write_attribute("val", "109000");
    1978         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    1979         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    1980         [ +  + ]:             82 :     write_attribute("val", "81000");
    1981         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    1982         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    1983         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    1984                 :                : 
    1985         [ +  + ]:             82 :     write_end_element(xmlns_a, "gsLst");
    1986                 :                : 
    1987         [ +  + ]:             82 :     write_start_element(xmlns_a, "lin");
    1988         [ +  + ]:             82 :     write_attribute("ang", "5400000");
    1989         [ +  + ]:             82 :     write_attribute("scaled", "0");
    1990         [ +  + ]:             82 :     write_end_element(xmlns_a, "lin");
    1991                 :                : 
    1992         [ +  + ]:             82 :     write_end_element(xmlns_a, "gradFill");
    1993                 :                : 
    1994         [ +  + ]:             82 :     write_start_element(xmlns_a, "gradFill");
    1995         [ +  + ]:             82 :     write_attribute("rotWithShape", "1");
    1996         [ +  + ]:             82 :     write_start_element(xmlns_a, "gsLst");
    1997                 :                : 
    1998         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    1999         [ +  + ]:             82 :     write_attribute("pos", "0");
    2000         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2001         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2002         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2003         [ +  + ]:             82 :     write_attribute("val", "103000");
    2004         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2005         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    2006         [ +  + ]:             82 :     write_attribute("val", "102000");
    2007         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    2008         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    2009         [ +  + ]:             82 :     write_attribute("val", "94000");
    2010         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    2011         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2012         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    2013                 :                : 
    2014         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    2015         [ +  + ]:             82 :     write_attribute("pos", "50000");
    2016         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2017         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2018         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2019         [ +  + ]:             82 :     write_attribute("val", "110000");
    2020         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2021         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    2022         [ +  + ]:             82 :     write_attribute("val", "100000");
    2023         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    2024         [ +  + ]:             82 :     write_start_element(xmlns_a, "shade");
    2025         [ +  + ]:             82 :     write_attribute("val", "100000");
    2026         [ +  + ]:             82 :     write_end_element(xmlns_a, "shade");
    2027         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2028         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    2029                 :                : 
    2030         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    2031         [ +  + ]:             82 :     write_attribute("pos", "100000");
    2032         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2033         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2034         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    2035         [ +  + ]:             82 :     write_attribute("val", "99000");
    2036         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    2037         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2038         [ +  + ]:             82 :     write_attribute("val", "120000");
    2039         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2040         [ +  + ]:             82 :     write_start_element(xmlns_a, "shade");
    2041         [ +  + ]:             82 :     write_attribute("val", "78000");
    2042         [ +  + ]:             82 :     write_end_element(xmlns_a, "shade");
    2043         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2044         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    2045                 :                : 
    2046         [ +  + ]:             82 :     write_end_element(xmlns_a, "gsLst");
    2047                 :                : 
    2048         [ +  + ]:             82 :     write_start_element(xmlns_a, "lin");
    2049         [ +  + ]:             82 :     write_attribute("ang", "5400000");
    2050         [ +  + ]:             82 :     write_attribute("scaled", "0");
    2051         [ +  + ]:             82 :     write_end_element(xmlns_a, "lin");
    2052                 :                : 
    2053         [ +  + ]:             82 :     write_end_element(xmlns_a, "gradFill");
    2054         [ +  + ]:             82 :     write_end_element(xmlns_a, "fillStyleLst");
    2055                 :                : 
    2056         [ +  + ]:             82 :     write_start_element(xmlns_a, "lnStyleLst");
    2057                 :                : 
    2058         [ +  + ]:             82 :     write_start_element(xmlns_a, "ln");
    2059         [ +  + ]:             82 :     write_attribute("w", "6350");
    2060         [ +  + ]:             82 :     write_attribute("cap", "flat");
    2061         [ +  + ]:             82 :     write_attribute("cmpd", "sng");
    2062         [ +  + ]:             82 :     write_attribute("algn", "ctr");
    2063         [ +  + ]:             82 :     write_start_element(xmlns_a, "solidFill");
    2064         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2065         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2066         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2067         [ +  + ]:             82 :     write_end_element(xmlns_a, "solidFill");
    2068         [ +  + ]:             82 :     write_start_element(xmlns_a, "prstDash");
    2069         [ +  + ]:             82 :     write_attribute("val", "solid");
    2070         [ +  + ]:             82 :     write_end_element(xmlns_a, "prstDash");
    2071         [ +  + ]:             82 :     write_start_element(xmlns_a, "miter");
    2072         [ +  + ]:             82 :     write_attribute("lim", "800000");
    2073         [ +  + ]:             82 :     write_end_element(xmlns_a, "miter");
    2074         [ +  + ]:             82 :     write_end_element(xmlns_a, "ln");
    2075                 :                : 
    2076         [ +  + ]:             82 :     write_start_element(xmlns_a, "ln");
    2077         [ +  + ]:             82 :     write_attribute("w", "12700");
    2078         [ +  + ]:             82 :     write_attribute("cap", "flat");
    2079         [ +  + ]:             82 :     write_attribute("cmpd", "sng");
    2080         [ +  + ]:             82 :     write_attribute("algn", "ctr");
    2081         [ +  + ]:             82 :     write_start_element(xmlns_a, "solidFill");
    2082         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2083         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2084         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2085         [ +  + ]:             82 :     write_end_element(xmlns_a, "solidFill");
    2086         [ +  + ]:             82 :     write_start_element(xmlns_a, "prstDash");
    2087         [ +  + ]:             82 :     write_attribute("val", "solid");
    2088         [ +  + ]:             82 :     write_end_element(xmlns_a, "prstDash");
    2089         [ +  + ]:             82 :     write_start_element(xmlns_a, "miter");
    2090         [ +  + ]:             82 :     write_attribute("lim", "800000");
    2091         [ +  + ]:             82 :     write_end_element(xmlns_a, "miter");
    2092         [ +  + ]:             82 :     write_end_element(xmlns_a, "ln");
    2093                 :                : 
    2094         [ +  + ]:             82 :     write_start_element(xmlns_a, "ln");
    2095         [ +  + ]:             82 :     write_attribute("w", "19050");
    2096         [ +  + ]:             82 :     write_attribute("cap", "flat");
    2097         [ +  + ]:             82 :     write_attribute("cmpd", "sng");
    2098         [ +  + ]:             82 :     write_attribute("algn", "ctr");
    2099         [ +  + ]:             82 :     write_start_element(xmlns_a, "solidFill");
    2100         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2101         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2102         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2103         [ +  + ]:             82 :     write_end_element(xmlns_a, "solidFill");
    2104         [ +  + ]:             82 :     write_start_element(xmlns_a, "prstDash");
    2105         [ +  + ]:             82 :     write_attribute("val", "solid");
    2106         [ +  + ]:             82 :     write_end_element(xmlns_a, "prstDash");
    2107         [ +  + ]:             82 :     write_start_element(xmlns_a, "miter");
    2108         [ +  + ]:             82 :     write_attribute("lim", "800000");
    2109         [ +  + ]:             82 :     write_end_element(xmlns_a, "miter");
    2110         [ +  + ]:             82 :     write_end_element(xmlns_a, "ln");
    2111                 :                : 
    2112         [ +  + ]:             82 :     write_end_element(xmlns_a, "lnStyleLst");
    2113                 :                : 
    2114         [ +  + ]:             82 :     write_start_element(xmlns_a, "effectStyleLst");
    2115                 :                : 
    2116         [ +  + ]:             82 :     write_start_element(xmlns_a, "effectStyle");
    2117         [ +  + ]:             82 :     write_element(xmlns_a, "effectLst", "");
    2118         [ +  + ]:             82 :     write_end_element(xmlns_a, "effectStyle");
    2119                 :                : 
    2120         [ +  + ]:             82 :     write_start_element(xmlns_a, "effectStyle");
    2121         [ +  + ]:             82 :     write_element(xmlns_a, "effectLst", "");
    2122         [ +  + ]:             82 :     write_end_element(xmlns_a, "effectStyle");
    2123                 :                : 
    2124         [ +  + ]:             82 :     write_start_element(xmlns_a, "effectStyle");
    2125         [ +  + ]:             82 :     write_start_element(xmlns_a, "effectLst");
    2126         [ +  + ]:             82 :     write_start_element(xmlns_a, "outerShdw");
    2127         [ +  + ]:             82 :     write_attribute("blurRad", "57150");
    2128         [ +  + ]:             82 :     write_attribute("dist", "19050");
    2129         [ +  + ]:             82 :     write_attribute("dir", "5400000");
    2130         [ +  + ]:             82 :     write_attribute("algn", "ctr");
    2131         [ +  + ]:             82 :     write_attribute("rotWithShape", "0");
    2132         [ +  + ]:             82 :     write_start_element(xmlns_a, "srgbClr");
    2133         [ +  + ]:             82 :     write_attribute("val", "000000");
    2134         [ +  + ]:             82 :     write_start_element(xmlns_a, "alpha");
    2135         [ +  + ]:             82 :     write_attribute("val", "63000");
    2136         [ +  + ]:             82 :     write_end_element(xmlns_a, "alpha");
    2137         [ +  + ]:             82 :     write_end_element(xmlns_a, "srgbClr");
    2138         [ +  + ]:             82 :     write_end_element(xmlns_a, "outerShdw");
    2139         [ +  + ]:             82 :     write_end_element(xmlns_a, "effectLst");
    2140         [ +  + ]:             82 :     write_end_element(xmlns_a, "effectStyle");
    2141                 :                : 
    2142         [ +  + ]:             82 :     write_end_element(xmlns_a, "effectStyleLst");
    2143                 :                : 
    2144         [ +  + ]:             82 :     write_start_element(xmlns_a, "bgFillStyleLst");
    2145                 :                : 
    2146         [ +  + ]:             82 :     write_start_element(xmlns_a, "solidFill");
    2147         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2148         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2149         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2150         [ +  + ]:             82 :     write_end_element(xmlns_a, "solidFill");
    2151                 :                : 
    2152         [ +  + ]:             82 :     write_start_element(xmlns_a, "solidFill");
    2153         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2154         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2155         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    2156         [ +  + ]:             82 :     write_attribute("val", "95000");
    2157         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    2158         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2159         [ +  + ]:             82 :     write_attribute("val", "170000");
    2160         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2161         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2162         [ +  + ]:             82 :     write_end_element(xmlns_a, "solidFill");
    2163                 :                : 
    2164         [ +  + ]:             82 :     write_start_element(xmlns_a, "gradFill");
    2165         [ +  + ]:             82 :     write_attribute("rotWithShape", "1");
    2166         [ +  + ]:             82 :     write_start_element(xmlns_a, "gsLst");
    2167                 :                : 
    2168         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    2169         [ +  + ]:             82 :     write_attribute("pos", "0");
    2170         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2171         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2172         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    2173         [ +  + ]:             82 :     write_attribute("val", "93000");
    2174         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    2175         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2176         [ +  + ]:             82 :     write_attribute("val", "150000");
    2177         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2178         [ +  + ]:             82 :     write_start_element(xmlns_a, "shade");
    2179         [ +  + ]:             82 :     write_attribute("val", "98000");
    2180         [ +  + ]:             82 :     write_end_element(xmlns_a, "shade");
    2181         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    2182         [ +  + ]:             82 :     write_attribute("val", "102000");
    2183         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    2184         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2185         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    2186                 :                : 
    2187         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    2188         [ +  + ]:             82 :     write_attribute("pos", "50000");
    2189         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2190         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2191         [ +  + ]:             82 :     write_start_element(xmlns_a, "tint");
    2192         [ +  + ]:             82 :     write_attribute("val", "98000");
    2193         [ +  + ]:             82 :     write_end_element(xmlns_a, "tint");
    2194         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2195         [ +  + ]:             82 :     write_attribute("val", "130000");
    2196         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2197         [ +  + ]:             82 :     write_start_element(xmlns_a, "shade");
    2198         [ +  + ]:             82 :     write_attribute("val", "90000");
    2199         [ +  + ]:             82 :     write_end_element(xmlns_a, "shade");
    2200         [ +  + ]:             82 :     write_start_element(xmlns_a, "lumMod");
    2201         [ +  + ]:             82 :     write_attribute("val", "103000");
    2202         [ +  + ]:             82 :     write_end_element(xmlns_a, "lumMod");
    2203         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2204         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    2205                 :                : 
    2206         [ +  + ]:             82 :     write_start_element(xmlns_a, "gs");
    2207         [ +  + ]:             82 :     write_attribute("pos", "100000");
    2208         [ +  + ]:             82 :     write_start_element(xmlns_a, "schemeClr");
    2209         [ +  + ]:             82 :     write_attribute("val", "phClr");
    2210         [ +  + ]:             82 :     write_start_element(xmlns_a, "shade");
    2211         [ +  + ]:             82 :     write_attribute("val", "63000");
    2212         [ +  + ]:             82 :     write_end_element(xmlns_a, "shade");
    2213         [ +  + ]:             82 :     write_start_element(xmlns_a, "satMod");
    2214         [ +  + ]:             82 :     write_attribute("val", "120000");
    2215         [ +  + ]:             82 :     write_end_element(xmlns_a, "satMod");
    2216         [ +  + ]:             82 :     write_end_element(xmlns_a, "schemeClr");
    2217         [ +  + ]:             82 :     write_end_element(xmlns_a, "gs");
    2218                 :                : 
    2219         [ +  + ]:             82 :     write_end_element(xmlns_a, "gsLst");
    2220                 :                : 
    2221         [ +  + ]:             82 :     write_start_element(xmlns_a, "lin");
    2222         [ +  + ]:             82 :     write_attribute("ang", "5400000");
    2223         [ +  + ]:             82 :     write_attribute("scaled", "0");
    2224         [ +  + ]:             82 :     write_end_element(xmlns_a, "lin");
    2225                 :                : 
    2226         [ +  + ]:             82 :     write_end_element(xmlns_a, "gradFill");
    2227                 :                : 
    2228         [ +  + ]:             82 :     write_end_element(xmlns_a, "bgFillStyleLst");
    2229         [ +  + ]:             82 :     write_end_element(xmlns_a, "fmtScheme");
    2230         [ +  + ]:             82 :     write_end_element(xmlns_a, "themeElements");
    2231                 :                : 
    2232         [ +  + ]:             82 :     write_element(xmlns_a, "objectDefaults", "");
    2233         [ +  + ]:             82 :     write_element(xmlns_a, "extraClrSchemeLst", "");
    2234                 :                : 
    2235         [ +  + ]:             82 :     write_start_element(xmlns_a, "extLst");
    2236         [ +  + ]:             82 :     write_start_element(xmlns_a, "ext");
    2237         [ +  + ]:             82 :     write_attribute("uri", "{05A4C25C-085E-4340-85A3-A5531E510DB2}");
    2238         [ +  + ]:             82 :     write_start_element(xmlns_thm15, "themeFamily");
    2239         [ +  + ]:             82 :     write_namespace(xmlns_thm15, "thm15");
    2240         [ +  + ]:             82 :     write_attribute("name", "Office Theme");
    2241         [ +  + ]:             82 :     write_attribute("id", "{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}");
    2242         [ +  + ]:             82 :     write_attribute("vid", "{4A3C46E8-61CC-4603-A589-7422A47A8E4A}");
    2243         [ +  + ]:             82 :     write_end_element(xmlns_thm15, "themeFamily");
    2244         [ +  + ]:             82 :     write_end_element(xmlns_a, "ext");
    2245         [ +  + ]:             82 :     write_end_element(xmlns_a, "extLst");
    2246                 :                : 
    2247         [ +  + ]:             41 :     write_end_element(xmlns_a, "theme");
    2248                 :                : 
    2249   [ +  +  +  + ]:             82 :     const auto workbook_rel = source_.manifest().relationship(path("/"), relationship_type::office_document);
    2250   [ +  +  +  +  :            205 :     const auto theme_part = source_.manifest().canonicalize({workbook_rel, theme_rel});
                +  -  - ]
    2251         [ +  + ]:             41 :     const auto theme_rels = source_.manifest().relationships(theme_part);
    2252                 :                : 
    2253         [ +  + ]:             41 :     if (!theme_rels.empty())
    2254                 :                :     {
    2255            [ + ]:              1 :         write_relationships(theme_rels, theme_part);
    2256                 :                : 
    2257      [ +  +  + ]:              2 :         for (auto rel : theme_rels)
    2258                 :                :         {
    2259      [ +  +  - ]:              1 :             if (rel.type() == relationship_type::image)
    2260                 :                :             {
    2261   [ +  +  +  +  :              6 :                 const auto image_path = source_.manifest().canonicalize({workbook_rel, theme_rel, rel});
                +  -  - ]
    2262            [ + ]:              1 :                 write_image(image_path);
    2263                 :              1 :             }
    2264                 :              1 :         }
    2265                 :                :     }
    2266   [ +  +  +  +  :            167 : }
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                   -  - ]
    2267                 :                : 
    2268                 :UBC           0 : void xlsx_producer::write_volatile_dependencies(const relationship & /*rel*/)
    2269                 :                : {
    2270   [ #  #  #  # ]:              0 :     write_start_element(constants::ns("spreadsheetml"), "volTypes");
    2271   [ #  #  #  # ]:              0 :     write_end_element(constants::ns("spreadsheetml"), "volTypes");
    2272                 :              0 : }
    2273                 :                : 
    2274                 :CBC          53 : void xlsx_producer::write_worksheet(const relationship &rel)
    2275                 :                : {
    2276   [ +  +  +  -  :             55 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    2277   [ +  +  +  -  :             55 :     static const auto &xmlns_r = constants::ns("r");
             +  +  -  - ]
    2278   [ +  +  +  -  :             55 :     static const auto &xmlns_mc = constants::ns("mc");
             +  +  -  - ]
    2279   [ +  +  +  -  :             55 :     static const auto &xmlns_x14ac = constants::ns("x14ac");
             +  +  -  - ]
    2280                 :                : 
    2281   [ +  +  +  +  :             53 :     auto worksheet_part = rel.source().path().parent().append(rel.target().path());
                   +  + ]
    2282         [ +  + ]:             53 :     auto worksheet_rels = source_.manifest().relationships(worksheet_part);
    2283                 :                : 
    2284            [ + ]:             53 :     auto title = std::find_if(source_.d_->sheet_title_rel_id_map_.begin(), source_.d_->sheet_title_rel_id_map_.end(),
    2285                 :             64 :         [&](const std::pair<std::string, std::string> &p) {
    2286                 :             64 :             return p.second == rel.id();
    2287            [ + ]:             53 :         })->first;
    2288                 :                : 
    2289            [ + ]:             53 :     auto ws = source_.sheet_by_title(title);
    2290                 :                : 
    2291         [ +  + ]:            106 :     write_start_element(xmlns, "worksheet");
    2292         [ +  + ]:            106 :     write_namespace(xmlns, "");
    2293         [ +  + ]:             53 :     write_namespace(xmlns_r, "r");
    2294                 :                : 
    2295                 :             53 :     auto using_namespace = [&ws](const std::string &ns) {
    2296         [ +  - ]:             53 :         if (ns == "x14ac")
    2297                 :                :         {
    2298      [ +  +  + ]:             53 :             if (ws.format_properties().dy_descent.is_set())
    2299                 :                :             {
    2300                 :             30 :                 return true;
    2301                 :                :             }
    2302                 :                : 
    2303                 :             23 :             auto highest = ws.highest_row();
    2304         [ +  + ]:             97 :             for (auto row = ws.lowest_row(); row <= highest; ++row)
    2305                 :                :             {
    2306   [ +  +  -  +  :             74 :                 if (ws.has_row_properties(row) && ws.row_properties(row).dy_descent.is_set())
                   -  + ]
    2307                 :                :                 {
    2308                 :UBC           0 :                     return true;
    2309                 :                :                 }
    2310                 :                :             }
    2311                 :                :         }
    2312                 :                : 
    2313                 :CBC          23 :         return false;
    2314                 :             53 :     };
    2315                 :                : 
    2316   [ +  +  +  + ]:            106 :     if (using_namespace("x14ac"))
    2317                 :                :     {
    2318         [ +  + ]:             60 :         write_namespace(xmlns_mc, "mc");
    2319         [ +  + ]:             60 :         write_namespace(xmlns_x14ac, "x14ac");
    2320      [ +  +  + ]:             60 :         write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
    2321                 :                :     }
    2322                 :                : 
    2323         [ +  + ]:             53 :     if (ws.d_->sheet_properties_.is_set())
    2324                 :                :     {
    2325         [ +  + ]:              5 :         write_start_element(xmlns, "sheetPr");
    2326            [ + ]:              5 :         auto &props = ws.d_->sheet_properties_.get();
    2327         [ -  + ]:              5 :         if (props.sync_horizontal.is_set())
    2328                 :                :         {
    2329      [ #  #  # ]:UBC           0 :             write_attribute("syncHorizontal", props.sync_horizontal.get());
    2330                 :                :         }
    2331         [ -  + ]:CBC           5 :         if (props.sync_vertical.is_set())
    2332                 :                :         {
    2333      [ #  #  # ]:UBC           0 :             write_attribute("syncVertical", props.sync_vertical.get());
    2334                 :                :         }
    2335         [ -  + ]:CBC           5 :         if (props.sync_ref.is_set())
    2336                 :                :         {
    2337   [ #  #  #  # ]:UBC           0 :             write_attribute("syncRef", props.sync_ref.get().to_string());
    2338                 :                :         }
    2339         [ -  + ]:CBC           5 :         if (props.transition_evaluation.is_set())
    2340                 :                :         {
    2341      [ #  #  # ]:UBC           0 :             write_attribute("transitionEvaluation", props.transition_evaluation.get());
    2342                 :                :         }
    2343         [ -  + ]:CBC           5 :         if (props.transition_entry.is_set())
    2344                 :                :         {
    2345      [ #  #  # ]:UBC           0 :             write_attribute("transitionEntry", props.transition_entry.get());
    2346                 :                :         }
    2347         [ -  + ]:CBC           5 :         if (props.published.is_set())
    2348                 :                :         {
    2349      [ #  #  # ]:UBC           0 :             write_attribute("published", props.published.get());
    2350                 :                :         }
    2351         [ +  + ]:CBC           5 :         if (props.code_name.is_set())
    2352                 :                :         {
    2353   [ +  +  +  + ]:              3 :             write_attribute("codeName", props.code_name.get());
    2354                 :                :         }
    2355         [ +  + ]:              5 :         if (props.filter_mode.is_set())
    2356                 :                :         {
    2357      [ +  +  + ]:              6 :             write_attribute("filterMode", props.filter_mode.get());
    2358                 :                :         }
    2359         [ -  + ]:              5 :         if (props.enable_format_condition_calculation.is_set())
    2360                 :                :         {
    2361      [ #  #  # ]:UBC           0 :             write_attribute("enableFormatConditionsCalculation", props.enable_format_condition_calculation.get());
    2362                 :                :         }
    2363                 :                :         // outlinePr is optional in the spec but is being written every time?
    2364         [ +  + ]:CBC          10 :         write_start_element(xmlns, "outlinePr");
    2365         [ +  + ]:             10 :         write_attribute("summaryBelow", "1");
    2366         [ +  + ]:             10 :         write_attribute("summaryRight", "1");
    2367         [ +  + ]:              5 :         write_end_element(xmlns, "outlinePr");
    2368                 :                : 
    2369      [ +  +  + ]:              5 :         if (ws.has_page_setup())
    2370                 :                :         {
    2371         [ +  + ]:              4 :             write_start_element(xmlns, "pageSetUpPr");
    2372   [ +  +  +  +  :             12 :             write_attribute("fitToPage", write_bool(ws.page_setup().fit_to_page()));
                      + ]
    2373         [ +  + ]:              8 :             write_end_element(xmlns, "pageSetUpPr");
    2374                 :                :         }
    2375         [ +  + ]:             10 :         write_end_element(xmlns, "sheetPr");
    2376                 :                :     }
    2377                 :                : 
    2378         [ +  + ]:             53 :     write_start_element(xmlns, "dimension");
    2379            [ + ]:             53 :     const auto dimension = ws.calculate_dimension();
    2380      [ +  +  + ]:            159 :     write_attribute("ref", dimension.to_string());
    2381         [ +  + ]:             53 :     write_end_element(xmlns, "dimension");
    2382                 :                : 
    2383      [ +  +  + ]:             53 :     if (ws.has_view())
    2384                 :                :     {
    2385         [ +  + ]:            100 :         write_start_element(xmlns, "sheetViews");
    2386         [ +  + ]:             50 :         write_start_element(xmlns, "sheetView");
    2387                 :                : 
    2388         [ +  + ]:             50 :         const auto view = ws.view();
    2389                 :                : 
    2390         [ +  + ]:             50 :         if (!view.show_grid_lines())
    2391                 :                :         {
    2392      [ +  +  + ]:              3 :             write_attribute("showGridLines", write_bool(view.show_grid_lines()));
    2393                 :                :         }
    2394                 :                : 
    2395      [ +  +  + ]:             50 :         if (source_.has_view())
    2396                 :                :         {
    2397            [ + ]:             49 :             const auto wb_view = source_.view();
    2398                 :                : 
    2399   [ +  +  +  + ]:             97 :             if ((wb_view.active_tab.is_set() && (ws.id() - 1) == wb_view.active_tab.get())
    2400   [ +  +  +  +  :             97 :                 || (!wb_view.active_tab.is_set() && ws.id() == 1))
             +  +  -  +  
                      + ]
    2401                 :                :             {
    2402      [ +  +  + ]:            120 :                 write_attribute("tabSelected", write_bool(true));
    2403                 :                :             }
    2404                 :             49 :         }
    2405      [ +  +  - ]:              1 :         else if (ws.id() == 1)
    2406                 :                :         {
    2407      [ +  +  + ]:              3 :             write_attribute("tabSelected", write_bool(true));
    2408                 :                :         }
    2409                 :                : 
    2410         [ +  + ]:             50 :         if (view.type() != sheet_view_type::normal)
    2411                 :                :         {
    2412   [ -  +  +  + ]:              6 :             write_attribute("view", view.type() == sheet_view_type::page_break_preview ? "pageBreakPreview" : "pageLayout");
    2413                 :                :         }
    2414         [ +  + ]:             50 :         if (view.has_top_left_cell())
    2415                 :                :         {
    2416   [ +  +  +  + ]:              9 :             write_attribute("topLeftCell", view.top_left_cell().to_string());
    2417                 :                :         }
    2418                 :                : 
    2419         [ +  + ]:            100 :         write_attribute("workbookViewId", view.id());
    2420                 :                : 
    2421         [ +  + ]:             50 :         if (view.zoom_scale() != 100)
    2422                 :                :         {
    2423         [ +  + ]:              6 :             write_attribute("zoomScale", view.zoom_scale());
    2424                 :                :         }
    2425                 :                : 
    2426         [ +  + ]:             50 :         if (view.has_pane())
    2427                 :                :         {
    2428            [ + ]:              2 :             const auto &current_pane = view.pane();
    2429         [ +  + ]:              2 :             write_start_element(xmlns, "pane"); // CT_Pane
    2430                 :                : 
    2431         [ +  - ]:              2 :             if (current_pane.top_left_cell.is_set())
    2432                 :                :             {
    2433   [ +  +  +  + ]:              6 :                 write_attribute("topLeftCell", current_pane.top_left_cell.get().to_string());
    2434                 :                :             }
    2435                 :                : 
    2436   [ +  +  +  +  :              2 :             if (current_pane.x_split + 1 == current_pane.top_left_cell.get().column())
                +  +  - ]
    2437                 :                :             {
    2438         [ +  + ]:              6 :                 write_attribute("xSplit", current_pane.x_split.index);
    2439                 :                :             }
    2440                 :                : 
    2441   [ +  +  +  - ]:              2 :             if (current_pane.y_split + 1 == current_pane.top_left_cell.get().row())
    2442                 :                :             {
    2443         [ +  + ]:              6 :                 write_attribute("ySplit", current_pane.y_split);
    2444                 :                :             }
    2445                 :                : 
    2446         [ +  - ]:              2 :             if (current_pane.active_pane != pane_corner::top_left)
    2447                 :                :             {
    2448         [ +  + ]:              6 :                 write_attribute("activePane", current_pane.active_pane);
    2449                 :                :             }
    2450                 :                : 
    2451         [ +  - ]:              2 :             if (current_pane.state != pane_state::split)
    2452                 :                :             {
    2453         [ +  + ]:              6 :                 write_attribute("state", current_pane.state);
    2454                 :                :             }
    2455                 :                : 
    2456         [ +  + ]:              4 :             write_end_element(xmlns, "pane");
    2457                 :                :         }
    2458                 :                : 
    2459      [ +  +  + ]:             77 :         for (const auto &current_selection : view.selections())
    2460                 :                :         {
    2461         [ +  + ]:             27 :             write_start_element(xmlns, "selection"); // CT_Selection
    2462                 :                : 
    2463         [ +  + ]:             27 :             if (current_selection.has_active_cell())
    2464                 :                :             {
    2465   [ +  +  +  + ]:             75 :                 write_attribute("activeCell", current_selection.active_cell().to_string());
    2466                 :                :             }
    2467                 :                : 
    2468         [ +  - ]:             27 :             if (current_selection.has_sqref())
    2469                 :                :             {
    2470            [ + ]:             27 :                 std::string refs = detail::join(current_selection.sqrefs(), ' ');
    2471      [ +  +  + ]:             81 :                 write_attribute("sqref", refs);
    2472                 :             27 :             }
    2473                 :                : 
    2474         [ +  + ]:             27 :             if (current_selection.pane() != pane_corner::top_left)
    2475                 :                :             {
    2476         [ +  + ]:             12 :                 write_attribute("pane", current_selection.pane());
    2477                 :                :             }
    2478                 :                : 
    2479         [ +  + ]:             54 :             write_end_element(xmlns, "selection");
    2480                 :             50 :         }
    2481                 :                : 
    2482         [ +  + ]:            100 :         write_end_element(xmlns, "sheetView");
    2483         [ +  + ]:             50 :         write_end_element(xmlns, "sheetViews");
    2484                 :             50 :     }
    2485                 :                : 
    2486         [ +  + ]:             53 :     write_start_element(xmlns, "sheetFormatPr");
    2487                 :             53 :     const auto &format_properties = ws.d_->format_properties_;
    2488                 :                : 
    2489         [ +  + ]:             53 :     if (format_properties.base_col_width.is_set())
    2490                 :                :     {
    2491         [ +  + ]:             86 :         write_attribute<double>("baseColWidth",
    2492            [ + ]:             43 :             format_properties.base_col_width.get());
    2493                 :                :     }
    2494         [ +  + ]:             53 :     if (format_properties.default_column_width.is_set())
    2495                 :                :     {
    2496         [ +  + ]:              8 :         write_attribute<double>("defaultColWidth",
    2497            [ + ]:              4 :             format_properties.default_column_width.get());
    2498                 :                :     }
    2499                 :                : 
    2500         [ +  + ]:             53 :     write_attribute<double>("defaultRowHeight",
    2501                 :             53 :         format_properties.default_row_height);
    2502                 :                : 
    2503         [ +  + ]:             53 :     if (format_properties.dy_descent.is_set())
    2504                 :                :     {
    2505      [ +  +  + ]:             60 :         write_attribute<double>(xml::qname(xmlns_x14ac, "dyDescent"),
    2506            [ + ]:             30 :             format_properties.dy_descent.get());
    2507                 :                :     }
    2508                 :                : 
    2509         [ +  + ]:             53 :     write_end_element(xmlns, "sheetFormatPr");
    2510                 :                : 
    2511                 :             53 :     bool has_column_properties = false;
    2512            [ + ]:             53 :     const auto first_column = ws.lowest_column_or_props();
    2513            [ + ]:             53 :     const auto last_column = ws.highest_column_or_props();
    2514                 :                : 
    2515   [ +  +  +  + ]:           1488 :     for (auto column = first_column; column <= last_column; column++)
    2516                 :                :     {
    2517      [ +  +  + ]:           1435 :         if (!ws.has_column_properties(column)) continue;
    2518                 :                : 
    2519         [ +  + ]:           1333 :         if (!has_column_properties)
    2520                 :                :         {
    2521         [ +  + ]:             15 :             write_start_element(xmlns, "cols");
    2522                 :             15 :             has_column_properties = true;
    2523                 :                :         }
    2524                 :                : 
    2525            [ + ]:           1333 :         const auto &props = ws.column_properties(column);
    2526                 :                : 
    2527         [ +  + ]:           1333 :         write_start_element(xmlns, "col");
    2528         [ +  + ]:           2666 :         write_attribute("min", column.index);
    2529         [ +  + ]:           2666 :         write_attribute("max", column.index);
    2530                 :                : 
    2531         [ +  - ]:           1333 :         if (props.width.is_set())
    2532                 :                :         {
    2533            [ + ]:           1333 :             double width = (props.width.get() * 7 + 5) / 7;
    2534      [ +  +  + ]:           3999 :             write_attribute("width", xlnt::detail::serialise(width));
    2535                 :                :         }
    2536                 :                : 
    2537         [ +  + ]:           1333 :         if (props.best_fit)
    2538                 :                :         {
    2539      [ +  +  + ]:             15 :             write_attribute("bestFit", write_bool(true));
    2540                 :                :         }
    2541                 :                : 
    2542         [ +  + ]:           1333 :         if (props.style.is_set())
    2543                 :                :         {
    2544      [ +  +  + ]:           3849 :             write_attribute("style", props.style.get());
    2545                 :                :         }
    2546                 :                : 
    2547         [ +  + ]:           1333 :         if (props.hidden)
    2548                 :                :         {
    2549      [ +  +  + ]:              6 :             write_attribute("hidden", write_bool(true));
    2550                 :                :         }
    2551                 :                : 
    2552         [ +  + ]:           1333 :         if (props.custom_width)
    2553                 :                :         {
    2554      [ +  +  + ]:            918 :             write_attribute("customWidth", write_bool(true));
    2555                 :                :         }
    2556                 :                : 
    2557         [ +  + ]:           2666 :         write_end_element(xmlns, "col");
    2558                 :                :     }
    2559                 :                : 
    2560         [ +  + ]:             53 :     if (has_column_properties)
    2561                 :                :     {
    2562         [ +  + ]:             30 :         write_end_element(xmlns, "cols");
    2563                 :                :     }
    2564                 :                : 
    2565                 :             53 :     std::vector<std::pair<std::string, hyperlink>> hyperlinks;
    2566                 :             53 :     std::vector<cell_reference> cells_with_comments;
    2567                 :                : 
    2568         [ +  + ]:             53 :     write_start_element(xmlns, "sheetData");
    2569            [ + ]:             53 :     auto first_row = ws.lowest_row_or_props();
    2570            [ + ]:             53 :     auto last_row = ws.highest_row_or_props();
    2571            [ + ]:             53 :     auto first_block_column = constants::max_column();
    2572            [ + ]:             53 :     auto last_block_column = constants::min_column();
    2573                 :                : 
    2574         [ +  + ]:           1715 :     for (auto row = first_row; row <= last_row; ++row)
    2575                 :                :     {
    2576                 :           1662 :         bool any_non_null = false;
    2577                 :           1662 :         auto first_check_row = row;
    2578                 :           1662 :         auto last_check_row = row;
    2579   [ +  +  +  + ]:           1662 :         auto first_row_in_block = row == first_row || row % 16 == 1;
    2580                 :                : 
    2581                 :                :         // See note for CT_Row, span attribute about block optimization
    2582         [ +  + ]:           1662 :         if (first_row_in_block)
    2583                 :                :         {
    2584                 :                :             // reset block column range
    2585            [ + ]:            146 :             first_block_column = constants::max_column();
    2586            [ + ]:            146 :             last_block_column = constants::min_column();
    2587                 :                : 
    2588                 :            146 :             first_check_row = row;
    2589                 :                :             // round up to the next multiple of 16
    2590                 :            146 :             last_check_row = ((row / 16) + 1) * 16;
    2591                 :                :         }
    2592                 :                : 
    2593         [ +  + ]:           5514 :         for (auto check_row = first_check_row; check_row <= last_check_row; ++check_row)
    2594                 :                :         {
    2595   [ +  +  +  +  :          10408 :             for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
             +  +  +  + ]
    2596                 :                :             {
    2597            [ + ]:           6556 :                 auto ref = cell_reference(column, check_row);
    2598            [ + ]:           6556 :                 auto cell = ws.d_->cell_map_.find(ref);
    2599         [ +  + ]:           6556 :                 if (cell == ws.d_->cell_map_.end())
    2600                 :                :                 {
    2601                 :           4779 :                     continue;
    2602                 :                :                 }
    2603         [ +  + ]:           1779 :                 if (cell->second.is_garbage_collectible())
    2604                 :                :                 {
    2605                 :              2 :                     continue;
    2606                 :                :                 }
    2607                 :                : 
    2608            [ + ]:           1777 :                 first_block_column = std::min(first_block_column, cell->second.column_);
    2609            [ + ]:           1777 :                 last_block_column = std::max(last_block_column, cell->second.column_);
    2610                 :                : 
    2611         [ +  + ]:           1777 :                 if (row == check_row)
    2612                 :                :                 {
    2613                 :            955 :                     any_non_null = true;
    2614                 :                :                 }
    2615                 :                :             }
    2616                 :                :         }
    2617                 :                : 
    2618   [ +  +  +  +  :           1662 :         if (!any_non_null && !ws.has_row_properties(row)) continue;
                +  +  + ]
    2619                 :                : 
    2620         [ +  + ]:           2600 :         write_start_element(xmlns, "row");
    2621         [ +  + ]:           1300 :         write_attribute("r", row);
    2622                 :                : 
    2623            [ + ]:           2600 :         auto span_string = std::to_string(first_block_column.index) + ":"
    2624            [ + ]:           3900 :             + std::to_string(last_block_column.index);
    2625      [ +  +  + ]:           3900 :         write_attribute("spans", span_string);
    2626                 :                : 
    2627      [ +  +  + ]:           1300 :         if (ws.has_row_properties(row))
    2628                 :                :         {
    2629            [ + ]:           1282 :             const auto &props = ws.row_properties(row);
    2630                 :                : 
    2631         [ +  + ]:           1282 :             if (props.style.is_set())
    2632                 :                :             {
    2633      [ +  +  + ]:              9 :                 write_attribute("s", props.style.get());
    2634                 :                :             }
    2635         [ +  + ]:           1282 :             if (props.custom_format.is_set())
    2636                 :                :             {
    2637   [ +  +  +  + ]:             12 :                 write_attribute("customFormat", write_bool(props.custom_format.get()));
    2638                 :                :             }
    2639                 :                : 
    2640         [ +  + ]:           1282 :             if (props.height.is_set())
    2641                 :                :             {
    2642            [ + ]:           1070 :                 auto height = props.height.get();
    2643      [ +  +  + ]:           3210 :                 write_attribute("ht", xlnt::detail::serialise(height));
    2644                 :                :             }
    2645                 :                : 
    2646         [ +  + ]:           1282 :             if (props.hidden)
    2647                 :                :             {
    2648      [ +  +  + ]:             18 :                 write_attribute("hidden", write_bool(true));
    2649                 :                :             }
    2650                 :                : 
    2651         [ +  + ]:           1282 :             if (props.custom_height)
    2652                 :                :             {
    2653      [ +  +  + ]:           3114 :                 write_attribute("customHeight", write_bool(true));
    2654                 :                :             }
    2655                 :                : 
    2656         [ +  + ]:           1282 :             if (props.dy_descent.is_set())
    2657                 :                :             {
    2658   [ +  +  +  + ]:            750 :                 write_attribute<double>(xml::qname(xmlns_x14ac, "dyDescent"), props.dy_descent.get());
    2659                 :                :             }
    2660                 :                :         }
    2661                 :                : 
    2662         [ +  + ]:           1300 :         if (any_non_null)
    2663                 :                :         {
    2664   [ +  +  +  +  :           1399 :             for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
             +  +  +  + ]
    2665                 :                :             {
    2666   [ +  +  +  + ]:           1108 :                 if (!ws.has_cell(cell_reference(column, row))) continue;
    2667                 :                : 
    2668         [ +  + ]:            956 :                 auto cell = ws.cell(cell_reference(column, row));
    2669                 :                : 
    2670      [ +  +  + ]:            956 :                 if (cell.garbage_collectible()) continue;
    2671                 :                : 
    2672                 :                :                 // record data about the cell needed later
    2673                 :                : 
    2674      [ +  +  + ]:            955 :                 if (cell.has_comment())
    2675                 :                :                 {
    2676         [ +  + ]:             16 :                     cells_with_comments.push_back(cell.reference());
    2677                 :                :                 }
    2678                 :                : 
    2679      [ +  +  + ]:            955 :                 if (cell.has_hyperlink())
    2680                 :                :                 {
    2681   [ +  +  +  + ]:             20 :                     hyperlinks.push_back(std::make_pair(cell.reference().to_string(), cell.hyperlink()));
    2682                 :                :                 }
    2683                 :                : 
    2684         [ +  + ]:            955 :                 write_start_element(xmlns, "c");
    2685                 :                : 
    2686                 :                :                 // begin cell attributes
    2687                 :                : 
    2688   [ +  +  +  + ]:           2865 :                 write_attribute("r", cell.reference().to_string());
    2689                 :                : 
    2690      [ +  +  + ]:            955 :                 if (cell.phonetics_visible())
    2691                 :                :                 {
    2692      [ +  +  + ]:              6 :                     write_attribute("ph", write_bool(true));
    2693                 :                :                 }
    2694                 :                : 
    2695      [ +  +  + ]:            955 :                 if (cell.has_format())
    2696                 :                :                 {
    2697      [ +  +  + ]:            987 :                     write_attribute("s", cell.format().d_->id);
    2698                 :                :                 }
    2699                 :                : 
    2700   [ +  +  +  -  :            955 :                 switch (cell.data_type())
          -  -  +  +  +  
                      - ]
    2701                 :                :                 {
    2702                 :            169 :                 case cell::type::empty:
    2703                 :            169 :                     break;
    2704                 :                : 
    2705                 :              2 :                 case cell::type::boolean:
    2706         [ +  + ]:              2 :                     write_attribute("t", "b");
    2707                 :              2 :                     break;
    2708                 :                : 
    2709                 :UBC           0 :                 case cell::type::date:
    2710         [ #  # ]:              0 :                     write_attribute("t", "d");
    2711                 :              0 :                     break;
    2712                 :                : 
    2713                 :              0 :                 case cell::type::error:
    2714         [ #  # ]:              0 :                     write_attribute("t", "e");
    2715                 :              0 :                     break;
    2716                 :                : 
    2717                 :              0 :                 case cell::type::inline_string:
    2718         [ #  # ]:              0 :                     write_attribute("t", "inlineStr");
    2719                 :              0 :                     break;
    2720                 :                : 
    2721                 :CBC          46 :                 case cell::type::number: // default, don't write it
    2722                 :                :                     //write_attribute("t", "n");
    2723                 :             46 :                     break;
    2724                 :                : 
    2725                 :            732 :                 case cell::type::shared_string:
    2726         [ +  + ]:            732 :                     write_attribute("t", "s");
    2727                 :            732 :                     break;
    2728                 :                : 
    2729                 :              6 :                 case cell::type::formula_string:
    2730         [ +  + ]:              6 :                     write_attribute("t", "str");
    2731                 :              6 :                     break;
    2732                 :                :                 }
    2733                 :                : 
    2734                 :                :                 //write_attribute("cm", "");
    2735                 :                :                 //write_attribute("vm", "");
    2736                 :                :                 //write_attribute("ph", "");
    2737                 :                : 
    2738                 :                :                 // begin child elements
    2739                 :                : 
    2740      [ +  +  + ]:            955 :                 if (cell.has_formula())
    2741                 :                :                 {
    2742      [ +  +  + ]:             27 :                     write_element(xmlns, "f", cell.formula());
    2743                 :                :                 }
    2744                 :                : 
    2745   [ +  +  +  -  :            955 :                 switch (cell.data_type())
          -  -  +  +  +  
                      - ]
    2746                 :                :                 {
    2747                 :            169 :                 case cell::type::empty:
    2748                 :            169 :                     break;
    2749                 :                : 
    2750                 :              2 :                 case cell::type::boolean:
    2751   [ +  +  +  + ]:              6 :                     write_element(xmlns, "v", write_bool(cell.value<bool>()));
    2752                 :              2 :                     break;
    2753                 :                : 
    2754                 :UBC           0 :                 case cell::type::date:
    2755      [ #  #  # ]:              0 :                     write_element(xmlns, "v", cell.value<std::string>());
    2756                 :              0 :                     break;
    2757                 :                : 
    2758                 :              0 :                 case cell::type::error:
    2759      [ #  #  # ]:              0 :                     write_element(xmlns, "v", cell.value<std::string>());
    2760                 :              0 :                     break;
    2761                 :                : 
    2762                 :              0 :                 case cell::type::inline_string:
    2763         [ #  # ]:              0 :                     write_start_element(xmlns, "is");
    2764         [ #  # ]:              0 :                     write_rich_text(xmlns, cell.value<xlnt::rich_text>());
    2765         [ #  # ]:              0 :                     write_end_element(xmlns, "is");
    2766                 :              0 :                     break;
    2767                 :                : 
    2768                 :CBC          46 :                 case cell::type::number:
    2769         [ +  + ]:             46 :                     write_start_element(xmlns, "v");
    2770      [ +  +  + ]:             46 :                     write_characters(xlnt::detail::serialise(cell.value<double>()));
    2771         [ +  + ]:             46 :                     write_end_element(xmlns, "v");
    2772                 :             46 :                     break;
    2773                 :                : 
    2774                 :            732 :                 case cell::type::shared_string:
    2775         [ +  + ]:           1464 :                     write_element(xmlns, "v", static_cast<std::size_t>(cell.d_->value_numeric_));
    2776                 :            732 :                     break;
    2777                 :                : 
    2778                 :              6 :                 case cell::type::formula_string:
    2779      [ +  +  + ]:             18 :                     write_element(xmlns, "v", cell.value<std::string>());
    2780                 :              6 :                     break;
    2781                 :                :                 }
    2782                 :                : 
    2783         [ +  + ]:           1910 :                 write_end_element(xmlns, "c");
    2784                 :                :             }
    2785                 :                :         }
    2786                 :                : 
    2787         [ +  + ]:           1300 :         write_end_element(xmlns, "row");
    2788                 :           1300 :     }
    2789                 :                : 
    2790         [ +  + ]:             53 :     write_end_element(xmlns, "sheetData");
    2791                 :                : 
    2792      [ +  +  + ]:             53 :     if (ws.has_auto_filter())
    2793                 :                :     {
    2794         [ +  + ]:              1 :         write_start_element(xmlns, "autoFilter");
    2795   [ +  +  +  + ]:              3 :         write_attribute("ref", ws.auto_filter().to_string());
    2796         [ +  + ]:              2 :         write_end_element(xmlns, "autoFilter");
    2797                 :                :     }
    2798                 :                : 
    2799      [ +  +  + ]:             53 :     if (!ws.merged_ranges().empty())
    2800                 :                :     {
    2801         [ +  + ]:              1 :         write_start_element(xmlns, "mergeCells");
    2802      [ +  +  + ]:              3 :         write_attribute("count", ws.merged_ranges().size());
    2803                 :                : 
    2804      [ +  +  + ]:              2 :         for (auto merged_range : ws.merged_ranges())
    2805                 :                :         {
    2806         [ +  + ]:              1 :             write_start_element(xmlns, "mergeCell");
    2807      [ +  +  + ]:              3 :             write_attribute("ref", merged_range.to_string());
    2808         [ +  + ]:              2 :             write_end_element(xmlns, "mergeCell");
    2809                 :              1 :         }
    2810                 :                : 
    2811         [ +  + ]:              2 :         write_end_element(xmlns, "mergeCells");
    2812                 :                :     }
    2813                 :                : 
    2814      [ +  +  + ]:             53 :     if (source_.impl().stylesheet_.is_set())
    2815                 :                :     {
    2816         [ +  + ]:             51 :         const auto &stylesheet = source_.impl().stylesheet_.get();
    2817                 :             51 :         const auto &cf_impls = stylesheet.conditional_format_impls;
    2818                 :                : 
    2819                 :             51 :         std::unordered_map<std::string, std::vector<const conditional_format_impl *>> range_map;
    2820                 :                : 
    2821         [ -  + ]:             51 :         for (auto &cf : cf_impls)
    2822                 :                :         {
    2823         [ #  # ]:UBC           0 :             if (cf.target_sheet != ws.d_) continue;
    2824                 :                : 
    2825   [ #  #  #  # ]:              0 :             if (range_map.find(cf.target_range.to_string()) == range_map.end())
    2826                 :                :             {
    2827      [ #  #  # ]:              0 :                 range_map[cf.target_range.to_string()] = {};
    2828                 :                :             }
    2829                 :                : 
    2830      [ #  #  # ]:              0 :             range_map[cf.target_range.to_string()].push_back(&cf);
    2831                 :                :         }
    2832                 :                : 
    2833         [ -  + ]:CBC          51 :         for (const auto &range_rules_pair : range_map)
    2834                 :                :         {
    2835         [ #  # ]:UBC           0 :             write_start_element(xmlns, "conditionalFormatting");
    2836      [ #  #  # ]:              0 :             write_attribute("sqref", range_rules_pair.first);
    2837                 :                : 
    2838                 :              0 :             std::size_t i = 1;
    2839                 :                : 
    2840         [ #  # ]:              0 :             for (auto rule : range_rules_pair.second)
    2841                 :                :             {
    2842         [ #  # ]:              0 :                 write_start_element(xmlns, "cfRule");
    2843         [ #  # ]:              0 :                 write_attribute("type", "containsText");
    2844         [ #  # ]:              0 :                 write_attribute("operator", "containsText");
    2845         [ #  # ]:              0 :                 write_attribute("dxfId", rule->differential_format_id);
    2846         [ #  # ]:              0 :                 write_attribute("priority", i++);
    2847      [ #  #  # ]:              0 :                 write_attribute("text", rule->when.text_comparand_);
    2848                 :                :                 //TODO: what does this formula mean and why is it necessary?
    2849   [ #  #  #  # ]:              0 :                 write_element(xmlns, "formula", "NOT(ISERROR(SEARCH(\"" + rule->when.text_comparand_ + "\",A1)))");
    2850         [ #  # ]:              0 :                 write_end_element(xmlns, "cfRule");
    2851                 :                :             }
    2852                 :                : 
    2853         [ #  # ]:              0 :             write_end_element(xmlns, "conditionalFormatting");
    2854                 :                :         }
    2855                 :CBC          51 :     }
    2856                 :                : 
    2857         [ +  + ]:             53 :     if (!hyperlinks.empty())
    2858                 :                :     {
    2859         [ +  + ]:              8 :         write_start_element(xmlns, "hyperlinks");
    2860                 :                : 
    2861         [ +  + ]:             28 :         for (const auto &hyperlink : hyperlinks)
    2862                 :                :         {
    2863         [ +  + ]:             20 :             write_start_element(xmlns, "hyperlink");
    2864      [ +  +  + ]:             60 :             write_attribute("ref", hyperlink.first);
    2865      [ +  +  + ]:             20 :             if (hyperlink.second.external())
    2866                 :                :             {
    2867      [ +  +  + ]:             32 :                 write_attribute(xml::qname(xmlns_r, "id"),
    2868      [ +  +  + ]:             32 :                     hyperlink.second.relationship().id());
    2869                 :                :             }
    2870                 :                :             else
    2871                 :                :             {
    2872      [ +  +  + ]:             12 :                 write_attribute("location", hyperlink.second.target_range());
    2873   [ +  +  +  + ]:             12 :                 write_attribute("display", hyperlink.second.display());
    2874                 :                :             }
    2875         [ +  + ]:             40 :             write_end_element(xmlns, "hyperlink");
    2876                 :                :         }
    2877                 :                : 
    2878         [ +  + ]:             16 :         write_end_element(xmlns, "hyperlinks");
    2879                 :                :     }
    2880                 :                : 
    2881      [ +  +  + ]:             53 :     if (ws.has_phonetic_properties())
    2882                 :                :     {
    2883         [ +  + ]:              4 :         write_start_element(xmlns, phonetic_pr::Serialised_ID());
    2884            [ + ]:              4 :         const auto &ph_props = ws.phonetic_properties();
    2885      [ +  +  + ]:              8 :         write_attribute("fontId", ph_props.font_id());
    2886      [ +  +  + ]:              4 :         if (ph_props.has_type())
    2887                 :                :         {
    2888   [ +  +  +  +  :              9 :             write_attribute("type", phonetic_pr::type_as_string(ph_props.type()));
                      + ]
    2889                 :                :         }
    2890      [ +  -  + ]:              4 :         if (ph_props.has_alignment())
    2891                 :                :         {
    2892   [ #  #  #  #  :UBC           0 :             write_attribute("alignment", phonetic_pr::alignment_as_string(ph_props.alignment()));
                      # ]
    2893                 :                :         }
    2894         [ +  + ]:CBC           4 :         write_end_element(xmlns, phonetic_pr::Serialised_ID());
    2895                 :                :     }
    2896                 :                : 
    2897         [ +  + ]:             53 :     if (ws.d_->print_options_.is_set())
    2898                 :                :     {
    2899            [ + ]:              2 :         auto &opts = ws.d_->print_options_.get();
    2900         [ +  + ]:              2 :         write_start_element(xmlns, "printOptions");
    2901         [ +  + ]:              2 :         if (opts.print_grid_lines.is_set())
    2902                 :                :         {
    2903   [ +  +  +  + ]:              3 :             write_attribute("gridLines", write_bool(opts.print_grid_lines.get()));
    2904                 :                :         }
    2905         [ +  + ]:              2 :         if (opts.grid_lines_set.is_set())
    2906                 :                :         {
    2907   [ +  +  +  + ]:              3 :             write_attribute("gridLineSet", write_bool(opts.grid_lines_set.get()));
    2908                 :                :         }
    2909         [ +  + ]:              2 :         if (opts.print_headings.is_set())
    2910                 :                :         {
    2911   [ +  +  +  + ]:              3 :             write_attribute("headings", write_bool(opts.print_headings.get()));
    2912                 :                :         }
    2913         [ +  + ]:              2 :         if (opts.horizontal_centered.is_set())
    2914                 :                :         {
    2915   [ +  +  +  + ]:              3 :             write_attribute("horizontalCentered", write_bool(opts.horizontal_centered.get()));
    2916                 :                :         }
    2917         [ +  + ]:              2 :         if (opts.vertical_centered.is_set())
    2918                 :                :         {
    2919   [ +  +  +  + ]:              3 :             write_attribute("verticalCentered", write_bool(opts.vertical_centered.get()));
    2920                 :                :         }
    2921         [ +  + ]:              4 :         write_end_element(xmlns, "printOptions");
    2922                 :                :     }
    2923                 :                : 
    2924      [ +  +  + ]:             53 :     if (ws.has_page_margins())
    2925                 :                :     {
    2926         [ +  + ]:             46 :         write_start_element(xmlns, "pageMargins");
    2927                 :                : 
    2928   [ +  +  +  + ]:             92 :         write_attribute<double>("left", ws.page_margins().left());
    2929   [ +  +  +  + ]:             92 :         write_attribute<double>("right", ws.page_margins().right());
    2930   [ +  +  +  + ]:             92 :         write_attribute<double>("top", ws.page_margins().top());
    2931   [ +  +  +  + ]:             92 :         write_attribute<double>("bottom", ws.page_margins().bottom());
    2932   [ +  +  +  + ]:             92 :         write_attribute<double>("header", ws.page_margins().header());
    2933   [ +  +  +  + ]:            138 :         write_attribute<double>("footer", ws.page_margins().footer());
    2934                 :                : 
    2935         [ +  + ]:             92 :         write_end_element(xmlns, "pageMargins");
    2936                 :                :     }
    2937                 :                : 
    2938      [ +  +  + ]:             53 :     if (ws.has_page_setup())
    2939                 :                :     {
    2940            [ + ]:              8 :         const xlnt::page_setup &ps = ws.page_setup();
    2941         [ +  + ]:              8 :         write_start_element(xmlns, "pageSetup");
    2942      [ +  +  - ]:              8 :         if (ws.page_setup().orientation_.is_set())
    2943                 :                :         {
    2944   [ +  +  +  + ]:             24 :             write_attribute("orientation", ws.page_setup().orientation_.get());
    2945                 :                :         }
    2946      [ +  +  + ]:              8 :         if (ws.page_setup().horizontal_dpi_.is_set())
    2947                 :                :         {
    2948   [ +  +  +  + ]:             15 :             write_attribute("horizontalDpi", ws.page_setup().horizontal_dpi_.get());
    2949                 :                :         }
    2950      [ +  +  + ]:              8 :         if (ws.page_setup().vertical_dpi_.is_set())
    2951                 :                :         {
    2952   [ +  +  +  + ]:             18 :             write_attribute("verticalDpi", ws.page_setup().vertical_dpi_.get());
    2953                 :                :         }
    2954                 :                : 
    2955      [ +  +  + ]:              8 :         if (ps.has_paper_size())
    2956                 :                :         {
    2957      [ +  +  + ]:              9 :             write_attribute("paperSize", static_cast<std::size_t>(ps.paper_size()));
    2958                 :                :         }
    2959                 :                : 
    2960      [ +  +  + ]:              8 :         if (ps.has_scale())
    2961                 :                :         {
    2962      [ +  +  + ]:              6 :             write_attribute("scale", ps.scale());
    2963                 :                :         }
    2964                 :                : 
    2965      [ +  +  + ]:              8 :         if (ps.has_rel_id())
    2966                 :                :         {
    2967   [ +  +  +  +  :              3 :             write_attribute(xml::qname(xmlns_r, "id"), ps.rel_id());
                      + ]
    2968                 :                :         }
    2969                 :                :         /*write_attribute("fitToHeight", write_bool(ws.page_setup().fit_to_height()));
    2970                 :                :         write_attribute("fitToWidth", write_bool(ws.page_setup().fit_to_width()));*/
    2971         [ +  + ]:              8 :         write_end_element(xmlns, "pageSetup");
    2972                 :              8 :     }
    2973                 :                : 
    2974      [ +  +  + ]:             53 :     if (ws.has_header_footer())
    2975                 :                :     {
    2976            [ + ]:              5 :         const auto hf = ws.header_footer();
    2977                 :                : 
    2978         [ +  + ]:              5 :         write_start_element(xmlns, "headerFooter");
    2979                 :                : 
    2980                 :              5 :         auto odd_header = std::string();
    2981                 :              5 :         auto odd_footer = std::string();
    2982                 :              5 :         auto even_header = std::string();
    2983                 :              5 :         auto even_footer = std::string();
    2984                 :              5 :         auto first_header = std::string();
    2985                 :              5 :         auto first_footer = std::string();
    2986                 :                : 
    2987                 :              5 :         const auto locations =
    2988                 :                :             {
    2989                 :                :                 header_footer::location::left,
    2990                 :                :                 header_footer::location::center,
    2991                 :              5 :                 header_footer::location::right};
    2992                 :                : 
    2993                 :                :         using xlnt::detail::encode_header_footer;
    2994                 :                : 
    2995         [ +  + ]:             20 :         for (auto location : locations)
    2996                 :                :         {
    2997      [ +  -  + ]:             15 :             if (hf.different_odd_even())
    2998                 :                :             {
    2999      [ #  #  # ]:UBC           0 :                 if (hf.has_odd_even_header(location))
    3000                 :                :                 {
    3001      [ #  #  # ]:              0 :                     odd_header.append(encode_header_footer(hf.odd_header(location), location));
    3002      [ #  #  # ]:              0 :                     even_header.append(encode_header_footer(hf.even_header(location), location));
    3003                 :                :                 }
    3004                 :                : 
    3005      [ #  #  # ]:              0 :                 if (hf.has_odd_even_footer(location))
    3006                 :                :                 {
    3007      [ #  #  # ]:              0 :                     odd_footer.append(encode_header_footer(hf.odd_footer(location), location));
    3008      [ #  #  # ]:              0 :                     even_footer.append(encode_header_footer(hf.even_footer(location), location));
    3009                 :                :                 }
    3010                 :                :             }
    3011                 :                :             else
    3012                 :                :             {
    3013      [ +  +  + ]:CBC          15 :                 if (hf.has_header(location))
    3014                 :                :                 {
    3015      [ +  +  + ]:              8 :                     odd_header.append(encode_header_footer(hf.header(location), location));
    3016                 :                :                 }
    3017                 :                : 
    3018      [ +  +  + ]:             15 :                 if (hf.has_footer(location))
    3019                 :                :                 {
    3020      [ +  +  + ]:              9 :                     odd_footer.append(encode_header_footer(hf.footer(location), location));
    3021                 :                :                 }
    3022                 :                :             }
    3023                 :                : 
    3024      [ +  -  + ]:             15 :             if (hf.different_first())
    3025                 :                :             {
    3026      [ #  #  # ]:UBC           0 :                 if (hf.has_first_page_header(location))
    3027                 :                :                 {
    3028      [ #  #  # ]:              0 :                     first_header.append(encode_header_footer(hf.first_page_header(location), location));
    3029                 :                :                 }
    3030                 :                : 
    3031      [ #  #  # ]:              0 :                 if (hf.has_first_page_footer(location))
    3032                 :                :                 {
    3033      [ #  #  # ]:              0 :                     first_footer.append(encode_header_footer(hf.first_page_footer(location), location));
    3034                 :                :                 }
    3035                 :                :             }
    3036                 :                :         }
    3037                 :                : 
    3038         [ +  + ]:CBC           5 :         if (!odd_header.empty())
    3039                 :                :         {
    3040      [ +  +  + ]:             12 :             write_element(xmlns, "oddHeader", odd_header);
    3041                 :                :         }
    3042                 :                : 
    3043         [ +  - ]:              5 :         if (!odd_footer.empty())
    3044                 :                :         {
    3045      [ +  +  + ]:             15 :             write_element(xmlns, "oddFooter", odd_footer);
    3046                 :                :         }
    3047                 :                : 
    3048         [ -  + ]:              5 :         if (!even_header.empty())
    3049                 :                :         {
    3050      [ #  #  # ]:UBC           0 :             write_element(xmlns, "evenHeader", even_header);
    3051                 :                :         }
    3052                 :                : 
    3053         [ -  + ]:CBC           5 :         if (!even_footer.empty())
    3054                 :                :         {
    3055      [ #  #  # ]:UBC           0 :             write_element(xmlns, "evenFooter", even_footer);
    3056                 :                :         }
    3057                 :                : 
    3058         [ -  + ]:CBC           5 :         if (!first_header.empty())
    3059                 :                :         {
    3060      [ #  #  # ]:UBC           0 :             write_element(xmlns, "firstHeader", first_header);
    3061                 :                :         }
    3062                 :                : 
    3063         [ -  + ]:CBC           5 :         if (!first_footer.empty())
    3064                 :                :         {
    3065      [ #  #  # ]:UBC           0 :             write_element(xmlns, "firstFooter", first_footer);
    3066                 :                :         }
    3067                 :                : 
    3068         [ +  + ]:CBC           5 :         write_end_element(xmlns, "headerFooter");
    3069                 :              5 :     }
    3070                 :                : 
    3071      [ +  -  + ]:             53 :     if (!ws.page_break_rows().empty())
    3072                 :                :     {
    3073         [ #  # ]:UBC           0 :         write_start_element(xmlns, "rowBreaks");
    3074                 :                : 
    3075      [ #  #  # ]:              0 :         write_attribute("count", ws.page_break_rows().size());
    3076      [ #  #  # ]:              0 :         write_attribute("manualBreakCount", ws.page_break_rows().size());
    3077                 :                : 
    3078      [ #  #  # ]:              0 :         for (auto break_id : ws.page_break_rows())
    3079                 :                :         {
    3080         [ #  # ]:              0 :             write_start_element(xmlns, "brk");
    3081         [ #  # ]:              0 :             write_attribute("id", break_id);
    3082         [ #  # ]:              0 :             write_attribute("max", 16383);
    3083         [ #  # ]:              0 :             write_attribute("man", 1);
    3084         [ #  # ]:              0 :             write_end_element(xmlns, "brk");
    3085                 :                :         }
    3086                 :                : 
    3087         [ #  # ]:              0 :         write_end_element(xmlns, "rowBreaks");
    3088                 :                :     }
    3089                 :                : 
    3090      [ +  -  + ]:CBC          53 :     if (!ws.page_break_columns().empty())
    3091                 :                :     {
    3092         [ #  # ]:UBC           0 :         write_start_element(xmlns, "colBreaks");
    3093                 :                : 
    3094      [ #  #  # ]:              0 :         write_attribute("count", ws.page_break_columns().size());
    3095      [ #  #  # ]:              0 :         write_attribute("manualBreakCount", ws.page_break_columns().size());
    3096                 :                : 
    3097      [ #  #  # ]:              0 :         for (auto break_id : ws.page_break_columns())
    3098                 :                :         {
    3099         [ #  # ]:              0 :             write_start_element(xmlns, "brk");
    3100         [ #  # ]:              0 :             write_attribute("id", break_id.index);
    3101         [ #  # ]:              0 :             write_attribute("max", 1048575);
    3102         [ #  # ]:              0 :             write_attribute("man", 1);
    3103         [ #  # ]:              0 :             write_end_element(xmlns, "brk");
    3104                 :                :         }
    3105                 :                : 
    3106         [ #  # ]:              0 :         write_end_element(xmlns, "colBreaks");
    3107                 :                :     }
    3108                 :                : 
    3109         [ +  + ]:CBC          53 :     if (!worksheet_rels.empty())
    3110                 :                :     {
    3111         [ +  + ]:             46 :         for (const auto &child_rel : worksheet_rels)
    3112                 :                :         {
    3113      [ +  +  + ]:             35 :             if (child_rel.type() == xlnt::relationship_type::vml_drawing)
    3114                 :                :             {
    3115         [ +  + ]:              8 :                 write_start_element(xmlns, "legacyDrawing");
    3116   [ +  +  +  +  :             24 :                 write_attribute(xml::qname(xmlns_r, "id"), child_rel.id());
                      + ]
    3117         [ +  + ]:             16 :                 write_end_element(xmlns, "legacyDrawing");
    3118                 :                :             }
    3119      [ +  +  + ]:             27 :             else if (child_rel.type() == xlnt::relationship_type::drawings)
    3120                 :                :             {
    3121         [ +  + ]:              2 :                 write_start_element(xmlns, "drawing");
    3122   [ +  +  +  +  :              6 :                 write_attribute(xml::qname(xmlns_r, "id"), child_rel.id());
                      + ]
    3123         [ +  + ]:              4 :                 write_end_element(xmlns, "drawing");
    3124                 :                :             }
    3125                 :                :         }
    3126                 :                :     }
    3127                 :                : 
    3128         [ +  + ]:             53 :     if (ws.d_->extension_list_.is_set())
    3129                 :                :     {
    3130         [ +  + ]:              2 :         ws.d_->extension_list_.get().serialize(*current_part_serializer_, xmlns);
    3131                 :                :     }
    3132                 :                : 
    3133         [ +  + ]:             53 :     write_end_element(xmlns, "worksheet");
    3134                 :                : 
    3135         [ +  + ]:             53 :     if (!worksheet_rels.empty())
    3136                 :                :     {
    3137            [ + ]:             11 :         write_relationships(worksheet_rels, worksheet_part);
    3138                 :                : 
    3139         [ +  + ]:             46 :         for (const auto &child_rel : worksheet_rels)
    3140                 :                :         {
    3141      [ +  +  + ]:             36 :             if (child_rel.target_mode() == target_mode::external) continue;
    3142                 :                : 
    3143                 :                :             // todo: this is ugly
    3144   [ +  +  +  + ]:             19 :             path archive_path(worksheet_part.parent().append(child_rel.target().path()));
    3145            [ + ]:             19 :             auto split_part_path = archive_path.split();
    3146                 :             19 :             auto part_path_iter = split_part_path.begin();
    3147                 :                : 
    3148         [ +  + ]:            106 :             while (part_path_iter != split_part_path.end())
    3149                 :                :             {
    3150      [ +  +  + ]:             87 :                 if (*part_path_iter == "..")
    3151                 :                :                 {
    3152            [ + ]:             19 :                     part_path_iter = split_part_path.erase(part_path_iter - 1, part_path_iter + 1);
    3153                 :             19 :                     continue;
    3154                 :                :                 }
    3155                 :                : 
    3156                 :             68 :                 ++part_path_iter;
    3157                 :                :             }
    3158                 :                : 
    3159      [ +  +  + ]:             38 :             archive_path = std::accumulate(split_part_path.begin(), split_part_path.end(), path(""),
    3160                 :             68 :                 [](const path &a, const std::string &b) { return a.append(b); });
    3161                 :                : 
    3162      [ +  +  + ]:             19 :             if (child_rel.type() == relationship_type::printer_settings)
    3163                 :                :             {
    3164            [ + ]:              1 :                 write_binary(archive_path);
    3165                 :              1 :                 continue;
    3166                 :                :             }
    3167                 :                : 
    3168            [ + ]:             18 :             begin_part(archive_path);
    3169                 :                : 
    3170      [ +  +  + ]:             18 :             if (child_rel.type() == relationship_type::comments)
    3171                 :                :             {
    3172         [ +  + ]:              8 :                 write_comments(child_rel, ws, cells_with_comments);
    3173                 :                :             }
    3174      [ +  +  + ]:             10 :             else if (child_rel.type() == relationship_type::vml_drawing)
    3175                 :                :             {
    3176         [ +  + ]:              8 :                 write_vml_drawings(child_rel, ws, cells_with_comments);
    3177                 :                :             }
    3178      [ +  +  - ]:              2 :             else if (child_rel.type() == relationship_type::drawings)
    3179                 :                :             {
    3180         [ +  + ]:              2 :                 write_drawings(child_rel, ws);
    3181                 :                :             }
    3182   [ +  +  +  + ]:             20 :         }
    3183                 :                :     }
    3184                 :             53 : }
    3185                 :                : 
    3186                 :                : // Sheet Relationship Target Parts
    3187                 :                : 
    3188                 :              8 : void xlsx_producer::write_comments(const relationship & /*rel*/, worksheet ws, const std::vector<cell_reference> &cells)
    3189                 :                : {
    3190   [ +  +  +  -  :             10 :     static const auto &xmlns = constants::ns("spreadsheetml");
             +  +  -  - ]
    3191                 :                : 
    3192         [ +  + ]:             16 :     write_start_element(xmlns, "comments");
    3193         [ +  + ]:              8 :     write_namespace(xmlns, "");
    3194                 :                : 
    3195         [ +  - ]:              8 :     if (!cells.empty())
    3196                 :                :     {
    3197                 :              8 :         std::unordered_map<std::string, std::size_t> authors;
    3198                 :                : 
    3199         [ +  + ]:             24 :         for (auto cell_ref : cells)
    3200                 :                :         {
    3201            [ + ]:             16 :             auto cell = ws.cell(cell_ref);
    3202         [ +  + ]:             16 :             auto author = cell.comment().author();
    3203                 :                : 
    3204      [ +  +  + ]:             16 :             if (authors.find(author) == authors.end())
    3205                 :                :             {
    3206                 :              8 :                 auto author_index = authors.size();
    3207            [ + ]:              8 :                 authors[author] = author_index;
    3208                 :                :             }
    3209                 :             16 :         }
    3210                 :                : 
    3211         [ +  + ]:              8 :         write_start_element(xmlns, "authors");
    3212                 :                : 
    3213         [ +  + ]:             16 :         for (const auto &author : authors)
    3214                 :                :         {
    3215         [ +  + ]:              8 :             write_start_element(xmlns, "author");
    3216         [ +  + ]:              8 :             write_characters(author.first);
    3217         [ +  + ]:             16 :             write_end_element(xmlns, "author");
    3218                 :                :         }
    3219                 :                : 
    3220         [ +  + ]:             16 :         write_end_element(xmlns, "authors");
    3221         [ +  + ]:              8 :         write_start_element(xmlns, "commentList");
    3222                 :                : 
    3223         [ +  + ]:             24 :         for (const auto &cell_ref : cells)
    3224                 :                :         {
    3225         [ +  + ]:             16 :             write_start_element(xmlns, "comment");
    3226                 :                : 
    3227            [ + ]:             16 :             auto cell = ws.cell(cell_ref);
    3228            [ + ]:             16 :             auto cell_comment = cell.comment();
    3229                 :                : 
    3230      [ +  +  + ]:             48 :             write_attribute("ref", cell_ref.to_string());
    3231         [ +  + ]:             16 :             auto author_id = authors.at(cell_comment.author());
    3232         [ +  + ]:             32 :             write_attribute("authorId", author_id);
    3233                 :                : 
    3234         [ +  + ]:             16 :             write_start_element(xmlns, "text");
    3235         [ +  + ]:             16 :             write_rich_text(xmlns, cell_comment.text());
    3236         [ +  + ]:             32 :             write_end_element(xmlns, "text");
    3237                 :                : 
    3238         [ +  + ]:             16 :             write_end_element(xmlns, "comment");
    3239                 :             16 :         }
    3240                 :                : 
    3241         [ +  + ]:              8 :         write_end_element(xmlns, "commentList");
    3242                 :              8 :     }
    3243                 :                : 
    3244         [ +  + ]:              8 :     write_end_element(xmlns, "comments");
    3245                 :              8 : }
    3246                 :                : 
    3247                 :              8 : void xlsx_producer::write_vml_drawings(const relationship &rel, worksheet ws, const std::vector<cell_reference> &cells)
    3248                 :                : {
    3249   [ +  +  +  -  :             11 :     static const auto &xmlns_mv = std::string("http://macVmlSchemaUri");
                +  -  - ]
    3250   [ +  +  +  -  :             11 :     static const auto &xmlns_o = std::string("urn:schemas-microsoft-com:office:office");
                +  -  - ]
    3251   [ +  +  +  -  :             11 :     static const auto &xmlns_v = std::string("urn:schemas-microsoft-com:vml");
                +  -  - ]
    3252   [ +  +  +  -  :             11 :     static const auto &xmlns_x = std::string("urn:schemas-microsoft-com:office:excel");
                +  -  - ]
    3253                 :                : 
    3254         [ +  + ]:             16 :     write_start_element("xml");
    3255         [ +  + ]:             16 :     write_namespace(xmlns_v, "v");
    3256         [ +  + ]:             16 :     write_namespace(xmlns_o, "o");
    3257         [ +  + ]:             16 :     write_namespace(xmlns_x, "x");
    3258         [ +  + ]:             16 :     write_namespace(xmlns_mv, "mv");
    3259                 :                : 
    3260         [ +  + ]:             16 :     write_start_element(xmlns_o, "shapelayout");
    3261      [ +  +  + ]:             16 :     write_attribute(xml::qname(xmlns_v, "ext"), "edit");
    3262         [ +  + ]:             16 :     write_start_element(xmlns_o, "idmap");
    3263      [ +  +  + ]:              8 :     write_attribute(xml::qname(xmlns_v, "ext"), "edit");
    3264                 :                : 
    3265      [ +  +  + ]:              8 :     auto filename = rel.target().path().split_extension().first;
    3266                 :              8 :     auto index_pos = filename.size() - 1;
    3267                 :                : 
    3268   [ +  -  +  +  :             16 :     while (filename[index_pos] >= '0' && filename[index_pos] <= '9')
                   +  + ]
    3269                 :                :     {
    3270                 :              8 :         index_pos--;
    3271                 :                :     }
    3272                 :                : 
    3273                 :              8 :     size_t file_index = 0;
    3274         [ +  + ]:              8 :     detail::parse(filename.substr(index_pos + 1), file_index);
    3275                 :                : 
    3276         [ +  + ]:             24 :     write_attribute("data", file_index);
    3277         [ +  + ]:             16 :     write_end_element(xmlns_o, "idmap");
    3278         [ +  + ]:             16 :     write_end_element(xmlns_o, "shapelayout");
    3279                 :                : 
    3280         [ +  + ]:             16 :     write_start_element(xmlns_v, "shapetype");
    3281         [ +  + ]:             16 :     write_attribute("id", "_x0000_t202");
    3282         [ +  + ]:             16 :     write_attribute("coordsize", "21600,21600");
    3283      [ +  +  + ]:             16 :     write_attribute(xml::qname(xmlns_o, "spt"), "202");
    3284         [ +  + ]:             16 :     write_attribute("path", "m0,0l0,21600,21600,21600,21600,0xe");
    3285         [ +  + ]:             16 :     write_start_element(xmlns_v, "stroke");
    3286         [ +  + ]:             16 :     write_attribute("joinstyle", "miter");
    3287         [ +  + ]:             16 :     write_end_element(xmlns_v, "stroke");
    3288         [ +  + ]:             16 :     write_start_element(xmlns_v, "path");
    3289         [ +  + ]:             16 :     write_attribute("gradientshapeok", "t");
    3290      [ +  +  + ]:             16 :     write_attribute(xml::qname(xmlns_o, "connecttype"), "rect");
    3291         [ +  + ]:             16 :     write_end_element(xmlns_v, "path");
    3292         [ +  + ]:              8 :     write_end_element(xmlns_v, "shapetype");
    3293                 :                : 
    3294                 :              8 :     std::size_t comment_index = 0;
    3295                 :                : 
    3296         [ +  + ]:             24 :     for (const auto &cell_ref : cells)
    3297                 :                :     {
    3298         [ +  + ]:             16 :         auto comment = ws.cell(cell_ref).comment();
    3299                 :             16 :         auto shape_id = 1024 * file_index + 1 + comment_index * 2;
    3300                 :                : 
    3301         [ +  + ]:             16 :         write_start_element(xmlns_v, "shape");
    3302   [ +  +  +  + ]:             48 :         write_attribute("id", "_x0000_s" + std::to_string(shape_id));
    3303         [ +  + ]:             16 :         write_attribute("type", "#_x0000_t202");
    3304                 :                : 
    3305                 :             16 :         std::vector<std::pair<std::string, std::string>> style;
    3306                 :                : 
    3307         [ +  + ]:             16 :         style.push_back({"position", "absolute"});
    3308   [ +  +  +  + ]:             16 :         style.push_back({"margin-left", std::to_string(comment.left()) + "pt"});
    3309   [ +  +  +  + ]:             16 :         style.push_back({"margin-top", std::to_string(comment.top()) + "pt"});
    3310   [ +  +  +  + ]:             16 :         style.push_back({"width", std::to_string(comment.width()) + "pt"});
    3311   [ +  +  +  + ]:             16 :         style.push_back({"height", std::to_string(comment.height()) + "pt"});
    3312      [ +  +  + ]:             16 :         style.push_back({"z-index", std::to_string(comment_index + 1)});
    3313   [ +  -  +  +  :             16 :         style.push_back({"visibility", comment.visible() ? "visible" : "hidden"});
                      + ]
    3314                 :                : 
    3315                 :             16 :         std::string style_string;
    3316                 :                : 
    3317      [ +  +  + ]:            128 :         for (auto part : style)
    3318                 :                :         {
    3319            [ + ]:            112 :             style_string.append(part.first);
    3320            [ + ]:            112 :             style_string.append(":");
    3321            [ + ]:            112 :             style_string.append(part.second);
    3322            [ + ]:            112 :             style_string.append(";");
    3323                 :            112 :         }
    3324                 :                : 
    3325      [ +  +  + ]:             48 :         write_attribute("style", style_string);
    3326         [ +  + ]:             32 :         write_attribute("fillcolor", "#fbf6d6");
    3327         [ +  + ]:             32 :         write_attribute("strokecolor", "#edeaa1");
    3328                 :                : 
    3329         [ +  + ]:             32 :         write_start_element(xmlns_v, "fill");
    3330         [ +  + ]:             32 :         write_attribute("color2", "#fbfe82");
    3331         [ +  + ]:             32 :         write_attribute("angle", -180);
    3332         [ +  + ]:             32 :         write_attribute("type", "gradient");
    3333         [ +  + ]:             32 :         write_start_element(xmlns_o, "fill");
    3334      [ +  +  + ]:             32 :         write_attribute(xml::qname(xmlns_v, "ext"), "view");
    3335         [ +  + ]:             32 :         write_attribute("type", "gradientUnscaled");
    3336         [ +  + ]:             32 :         write_end_element(xmlns_o, "fill");
    3337         [ +  + ]:             32 :         write_end_element(xmlns_v, "fill");
    3338                 :                : 
    3339         [ +  + ]:             32 :         write_start_element(xmlns_v, "shadow");
    3340         [ +  + ]:             32 :         write_attribute("on", "t");
    3341         [ +  + ]:             32 :         write_attribute("obscured", "t");
    3342         [ +  + ]:             32 :         write_end_element(xmlns_v, "shadow");
    3343                 :                : 
    3344         [ +  + ]:             32 :         write_start_element(xmlns_v, "path");
    3345      [ +  +  + ]:             32 :         write_attribute(xml::qname(xmlns_o, "connecttype"), "none");
    3346         [ +  + ]:             32 :         write_end_element(xmlns_v, "path");
    3347                 :                : 
    3348         [ +  + ]:             32 :         write_start_element(xmlns_v, "textbox");
    3349         [ +  + ]:             32 :         write_attribute("style", "mso-direction-alt:auto");
    3350         [ +  + ]:             32 :         write_start_element("div");
    3351         [ +  + ]:             16 :         write_attribute("style", "text-align:left");
    3352            [ + ]:             16 :         write_characters("");
    3353         [ +  + ]:             32 :         write_end_element("div");
    3354         [ +  + ]:             32 :         write_end_element(xmlns_v, "textbox");
    3355                 :                : 
    3356         [ +  + ]:             32 :         write_start_element(xmlns_x, "ClientData");
    3357         [ +  + ]:             32 :         write_attribute("ObjectType", "Note");
    3358         [ +  + ]:             32 :         write_start_element(xmlns_x, "MoveWithCells");
    3359         [ +  + ]:             32 :         write_end_element(xmlns_x, "MoveWithCells");
    3360         [ +  + ]:             32 :         write_start_element(xmlns_x, "SizeWithCells");
    3361         [ +  + ]:             32 :         write_end_element(xmlns_x, "SizeWithCells");
    3362         [ +  + ]:             16 :         write_start_element(xmlns_x, "Anchor");
    3363   [ +  +  +  + ]:             16 :         write_characters("1, 15, 0, " + std::to_string(2 + comment_index * 4) + ", 2, 54, 4, 14");
    3364         [ +  + ]:             32 :         write_end_element(xmlns_x, "Anchor");
    3365         [ +  + ]:             16 :         write_start_element(xmlns_x, "AutoFill");
    3366            [ + ]:             16 :         write_characters("False");
    3367         [ +  + ]:             32 :         write_end_element(xmlns_x, "AutoFill");
    3368         [ +  + ]:             16 :         write_start_element(xmlns_x, "Row");
    3369         [ +  + ]:             16 :         write_characters(cell_ref.row() - 1);
    3370         [ +  + ]:             32 :         write_end_element(xmlns_x, "Row");
    3371         [ +  + ]:             16 :         write_start_element(xmlns_x, "Column");
    3372         [ +  + ]:             16 :         write_characters(cell_ref.column_index() - 1);
    3373         [ +  + ]:             32 :         write_end_element(xmlns_x, "Column");
    3374         [ +  + ]:             32 :         write_end_element(xmlns_x, "ClientData");
    3375                 :                : 
    3376         [ +  + ]:             16 :         write_end_element(xmlns_v, "shape");
    3377                 :                : 
    3378                 :             16 :         ++comment_index;
    3379                 :             16 :     }
    3380                 :                : 
    3381         [ +  + ]:              8 :     write_end_element("xml");
    3382                 :              8 : }
    3383                 :                : 
    3384                 :              2 : void xlsx_producer::write_drawings(const relationship &drawing_rel, worksheet ws)
    3385                 :                : {
    3386   [ +  +  +  + ]:              4 :     const auto workbook_rel = source_.manifest().relationship(path("/"), relationship_type::office_document);
    3387            [ + ]:              2 :     const auto worksheet_rel = ws.referring_relationship();
    3388   [ +  +  +  +  :             12 :     const auto drawing_part = source_.manifest().canonicalize({workbook_rel, worksheet_rel, drawing_rel});
                +  -  - ]
    3389         [ +  + ]:              2 :     const auto drawing_rels = source_.manifest().relationships(drawing_part);
    3390                 :                : 
    3391         [ +  - ]:              2 :     if (ws.d_->drawing_.is_set())
    3392                 :                :     {
    3393         [ +  + ]:              2 :         ws.d_->drawing_.get().serialize(*current_part_serializer_);
    3394                 :                :     }
    3395                 :                : 
    3396         [ +  + ]:              2 :     if (!drawing_rels.empty())
    3397                 :                :     {
    3398            [ + ]:              1 :         write_relationships(drawing_rels, drawing_part);
    3399                 :                : 
    3400      [ +  +  + ]:              2 :         for (auto rel : drawing_rels)
    3401                 :                :         {
    3402      [ +  +  - ]:              1 :             if (rel.type() == relationship_type::image)
    3403                 :                :             {
    3404   [ +  +  +  +  :              6 :                 const auto image_path = source_.manifest().canonicalize({workbook_rel, worksheet_rel, rel});
                +  -  - ]
    3405      [ +  -  + ]:              1 :                 if (image_path.string().find("cid:") != std::string::npos)
    3406                 :                :                 {
    3407                 :                :                     // skip cid attachments
    3408                 :UBC           0 :                     continue;
    3409                 :                :                 }
    3410            [ + ]:CBC           1 :                 write_image(image_path);
    3411         [ +  - ]:              1 :             }
    3412         [ +  - ]:              1 :         }
    3413                 :                :     }
    3414   [ +  +  +  +  :              5 : }
          +  +  -  -  -  
             -  -  -  -  
                      - ]
    3415                 :                : 
    3416                 :                : // Other Parts
    3417                 :                : 
    3418                 :UBC           0 : void xlsx_producer::write_custom_property()
    3419                 :                : {
    3420                 :              0 : }
    3421                 :                : 
    3422                 :              0 : void xlsx_producer::write_unknown_parts()
    3423                 :                : {
    3424                 :              0 : }
    3425                 :                : 
    3426                 :              0 : void xlsx_producer::write_unknown_relationships()
    3427                 :                : {
    3428                 :              0 : }
    3429                 :                : 
    3430                 :CBC          32 : void xlsx_producer::write_image(const path &image_path)
    3431                 :                : {
    3432                 :             32 :     end_part();
    3433                 :                : 
    3434      [ +  +  + ]:             32 :     vector_istreambuf buffer(source_.d_->images_.at(image_path.string()));
    3435            [ + ]:             32 :     auto image_streambuf = archive_->open(image_path);
    3436         [ +  + ]:             32 :     std::ostream(image_streambuf.get()) << &buffer;
    3437                 :             32 : }
    3438                 :                : 
    3439                 :              2 : void xlsx_producer::write_binary(const path &binary_path)
    3440                 :                : {
    3441                 :              2 :     end_part();
    3442                 :                : 
    3443      [ +  +  + ]:              2 :     vector_istreambuf buffer(source_.d_->binaries_.at(binary_path.string()));
    3444            [ + ]:              2 :     auto image_streambuf = archive_->open(binary_path);
    3445         [ +  + ]:              2 :     std::ostream(image_streambuf.get()) << &buffer;
    3446                 :              2 : }
    3447                 :                : 
    3448                 :           2244 : std::string xlsx_producer::write_bool(bool boolean) const
    3449                 :                : {
    3450      [ +  +  + ]:           4488 :     return boolean ? "1" : "0";
    3451                 :                : }
    3452                 :                : 
    3453                 :            101 : void xlsx_producer::write_relationships(const std::vector<xlnt::relationship> &relationships, const path &part)
    3454                 :                : {
    3455            [ + ]:            101 :     path parent = part.parent();
    3456                 :                : 
    3457      [ +  +  + ]:            101 :     if (parent.is_absolute())
    3458                 :                :     {
    3459      [ +  +  + ]:             44 :         parent = path(parent.string().substr(1));
    3460                 :                :     }
    3461                 :                : 
    3462   [ +  +  +  +  :            101 :     path rels_path(parent.append("_rels").append(part.filename() + ".rels").string());
                +  +  + ]
    3463            [ + ]:            101 :     begin_part(rels_path);
    3464                 :                : 
    3465      [ +  +  + ]:            202 :     const auto xmlns = xlnt::constants::ns("relationships");
    3466                 :                : 
    3467         [ +  + ]:            202 :     write_start_element(xmlns, "Relationships");
    3468         [ +  + ]:            101 :     write_namespace(xmlns, "");
    3469                 :                : 
    3470         [ +  + ]:            468 :     for (std::size_t i = 1; i <= relationships.size(); ++i)
    3471                 :                :     {
    3472            [ + ]:            367 :         auto rel_iter = std::find_if(relationships.begin(), relationships.end(),
    3473      [ +  +  + ]:            918 :             [&i](const relationship &r) { return r.id() == "rId" + std::to_string(i); });
    3474            [ + ]:            367 :         auto relationship = *rel_iter;
    3475                 :                : 
    3476         [ +  + ]:            367 :         write_start_element(xmlns, "Relationship");
    3477                 :                : 
    3478   [ +  +  +  + ]:           1101 :         write_attribute("Id", relationship.id());
    3479      [ +  +  + ]:            734 :         write_attribute("Type", relationship.type());
    3480   [ +  +  +  +  :           1101 :         write_attribute("Target", relationship.target().path().string());
                   +  + ]
    3481                 :                : 
    3482      [ +  +  + ]:            367 :         if (relationship.target_mode() == xlnt::target_mode::external)
    3483                 :                :         {
    3484         [ +  + ]:             32 :             write_attribute("TargetMode", "External");
    3485                 :                :         }
    3486                 :                : 
    3487         [ +  + ]:            367 :         write_end_element(xmlns, "Relationship");
    3488                 :            367 :     }
    3489                 :                : 
    3490         [ +  + ]:            101 :     write_end_element(xmlns, "Relationships");
    3491                 :            101 : }
    3492                 :                : 
    3493                 :            577 : void xlsx_producer::write_color(const xlnt::color &color)
    3494                 :                : {
    3495         [ +  + ]:            577 :     if (color.auto_())
    3496                 :                :     {
    3497      [ +  +  + ]:              6 :         write_attribute("auto", write_bool(true));
    3498                 :              2 :         return;
    3499                 :                :     }
    3500   [ +  +  +  - ]:            575 :     switch (color.type())
    3501                 :                :     {
    3502                 :            256 :     case xlnt::color_type::theme:
    3503         [ +  + ]:            512 :         write_attribute("theme", color.theme().index());
    3504                 :            256 :         break;
    3505                 :                : 
    3506                 :            173 :     case xlnt::color_type::indexed:
    3507         [ +  + ]:            346 :         write_attribute("indexed", color.indexed().index());
    3508                 :            173 :         break;
    3509                 :                : 
    3510                 :            146 :     case xlnt::color_type::rgb:
    3511   [ +  +  +  + ]:            438 :         write_attribute("rgb", color.rgb().hex_string());
    3512                 :            146 :         break;
    3513                 :                :     }
    3514         [ +  + ]:            575 :     if (color.has_tint())
    3515                 :                :     {
    3516   [ +  +  +  + ]:            240 :         write_attribute("tint", xlnt::detail::serialise(color.tint()));
    3517                 :                :     }
    3518                 :                : }
    3519                 :                : 
    3520                 :             24 : void xlsx_producer::write_start_element(const std::string &name)
    3521                 :                : {
    3522                 :             24 :     current_part_serializer_->start_element(name);
    3523                 :             24 : }
    3524                 :                : 
    3525                 :          20024 : void xlsx_producer::write_start_element(const std::string &ns, const std::string &name)
    3526                 :                : {
    3527                 :          20024 :     current_part_serializer_->start_element(ns, name);
    3528                 :          20024 : }
    3529                 :                : 
    3530                 :             24 : void xlsx_producer::write_end_element(const std::string &name)
    3531                 :                : {
    3532                 :             24 :     current_part_serializer_->end_element(name);
    3533                 :             24 : }
    3534                 :                : 
    3535                 :          20024 : void xlsx_producer::write_end_element(const std::string &ns, const std::string &name)
    3536                 :                : {
    3537                 :          20024 :     current_part_serializer_->end_element(ns, name);
    3538                 :          20024 : }
    3539                 :                : 
    3540                 :           1032 : void xlsx_producer::write_namespace(const std::string &ns, const std::string &prefix)
    3541                 :                : {
    3542                 :           1032 :     current_part_serializer_->namespace_decl(ns, prefix);
    3543                 :           1032 : }
    3544                 :                : 
    3545                 :                : } // namespace detail
    3546                 :                : } // namespace xlnt
        

Generated by: LCOV version 2.3.1-beta