LCOV - code coverage report
Current view: top level - core/vg - SPVectorImage.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 392 404 97.0 %
Date: 2024-05-12 00:16:13 Functions: 82 82 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPVectorImage.h"
      25             : #include "SPSvgReader.h"
      26             : 
      27             : #if MODULE_STAPPLER_BITMAP
      28             : #include "SPBitmap.h"
      29             : #endif
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::vg {
      32             : 
      33          75 : bool VectorPathRef::init(VectorImage *image, const String &id, const Rc<VectorPath> &path) {
      34          75 :         _image = image;
      35          75 :         _id = id;
      36          75 :         _path = path;
      37          75 :         return true;
      38             : }
      39             : 
      40      546628 : bool VectorPathRef::init(VectorImage *image, const String &id, Rc<VectorPath> &&path) {
      41      546628 :         _image = image;
      42      546628 :         _id = id;
      43      546628 :         _path = move(path);
      44      546628 :         return true;
      45             : }
      46             : 
      47          25 : size_t VectorPathRef::count() const {
      48          25 :         return _path ? _path->count() : 0;
      49             : }
      50             : 
      51          50 : VectorPathRef & VectorPathRef::setPath(BytesView bytes) {
      52          50 :         if (_path) {
      53          50 :                 _path->init(bytes);
      54             :         }
      55          50 :         return *this;
      56             : }
      57             : 
      58          25 : VectorPathRef & VectorPathRef::setPath(StringView str) {
      59          25 :         if (_path) {
      60          25 :                 _path->init(str);
      61             :         }
      62          25 :         return *this;
      63             : }
      64             : 
      65        5447 : VectorPathRef & VectorPathRef::openForWriting(const Callback<void(PathWriter &)> &cb) {
      66        5447 :         if (_copyOnWrite) {
      67           0 :                 copy();
      68             :         }
      69             : 
      70        5447 :         if (_path) {
      71        5447 :                 _path->openForWriting(cb);
      72        5447 :                 if (_image) { _image->setDirty(); }
      73             :         }
      74        5447 :         return *this;
      75             : }
      76             : 
      77        3997 : VectorPathRef & VectorPathRef::setFillColor(const Color4B &color) {
      78        3997 :         if (_path && _path->getFillColor() == color) {
      79             :                 return *this;
      80             :         }
      81             : 
      82          50 :         if (_copyOnWrite) {
      83          25 :                 copy();
      84             :         }
      85             : 
      86          50 :         if (_path) {
      87          50 :                 _path->setFillColor(color);
      88          50 :                 if (_image) { _image->setDirty(); }
      89             :         }
      90             :         return *this;
      91             : }
      92             : 
      93          25 : const Color4B &VectorPathRef::getFillColor() const {
      94          25 :         return _path ? _path->getFillColor() : Color4B::BLACK;
      95             : }
      96             : 
      97          25 : VectorPathRef & VectorPathRef::setStrokeColor(const Color4B &color) {
      98          25 :         if (_path && _path->getStrokeColor() == color) {
      99             :                 return *this;
     100             :         }
     101             : 
     102          25 :         if (_copyOnWrite) {
     103          25 :                 copy();
     104             :         }
     105             : 
     106          25 :         if (_path) {
     107          25 :                 _path->setStrokeColor(color);
     108          25 :                 if (_image) { _image->setDirty(); }
     109             :         }
     110             :         return *this;
     111             : }
     112             : 
     113          25 : const Color4B &VectorPathRef::getStrokeColor() const {
     114          25 :         return _path ? _path->getStrokeColor() : Color4B::BLACK;
     115             : }
     116             : 
     117        2823 : VectorPathRef & VectorPathRef::setFillOpacity(uint8_t value) {
     118        2823 :         if (_path && _path->getFillOpacity() == value) {
     119             :                 return *this;
     120             :         }
     121             : 
     122         279 :         if (_copyOnWrite) {
     123          25 :                 copy();
     124             :         }
     125             : 
     126         279 :         if (_path) {
     127         279 :                 _path->setFillOpacity(value);
     128         279 :                 if (_image) { _image->setDirty(); }
     129             :         }
     130             :         return *this;
     131             : }
     132       54511 : uint8_t VectorPathRef::getFillOpacity() const {
     133       54511 :         return _path ? _path->getFillOpacity() : 0;
     134             : }
     135             : 
     136          25 : VectorPathRef & VectorPathRef::setStrokeOpacity(uint8_t value) {
     137          25 :         if (_path && _path->getStrokeOpacity() == value) {
     138             :                 return *this;
     139             :         }
     140             : 
     141          25 :         if (_copyOnWrite) {
     142          25 :                 copy();
     143             :         }
     144             : 
     145          25 :         if (_path) {
     146          25 :                 _path->setStrokeOpacity(value);
     147          25 :                 if (_image) { _image->setDirty(); }
     148             :         }
     149             :         return *this;
     150             : }
     151             : 
     152          25 : uint8_t VectorPathRef::getStrokeOpacity() const {
     153          25 :         return _path ? _path->getStrokeOpacity() : 0;
     154             : }
     155             : 
     156      425650 : VectorPathRef & VectorPathRef::setStrokeWidth(float width) {
     157      425650 :         if (_path && _path->getStrokeWidth() == width) {
     158             :                 return *this;
     159             :         }
     160             : 
     161      425650 :         if (_copyOnWrite) {
     162          25 :                 copy();
     163             :         }
     164             : 
     165      425650 :         if (_path) {
     166      425650 :                 _path->setStrokeWidth(width);
     167      425650 :                 if (_image) { _image->setDirty(); }
     168             :         }
     169             :         return *this;
     170             : }
     171             : 
     172          25 : float VectorPathRef::getStrokeWidth() const {
     173          25 :         return _path ? _path->getStrokeWidth() : 0.0f;
     174             : }
     175             : 
     176       44896 : VectorPathRef &VectorPathRef::setWindingRule(vg::Winding value) {
     177       44896 :         if (_path && _path->getWindingRule() == value) {
     178             :                 return *this;
     179             :         }
     180             : 
     181       44896 :         if (_copyOnWrite) {
     182          25 :                 copy();
     183             :         }
     184             : 
     185       44896 :         if (_path) {
     186       44896 :                 _path->setWindingRule(value);
     187       44896 :                 if (_image) { _image->setDirty(); }
     188             :         }
     189             :         return *this;
     190             : }
     191             : 
     192          25 : vg::Winding VectorPathRef::getWindingRule() const {
     193          25 :         return _path ? _path->getWindingRule() : vg::Winding::NonZero;
     194             : }
     195             : 
     196      432370 : VectorPathRef & VectorPathRef::setStyle(vg::DrawStyle s) {
     197      432370 :         if (_path && _path->getStyle() == s) {
     198             :                 return *this;
     199             :         }
     200             : 
     201       77046 :         if (_copyOnWrite) {
     202           0 :                 copy();
     203             :         }
     204             : 
     205       77046 :         if (_path) {
     206       77046 :                 _path->setStyle(s);
     207       77046 :                 if (_image) { _image->setDirty(); }
     208             :         }
     209             :         return *this;
     210             : }
     211             : 
     212       57284 : vg::DrawStyle VectorPathRef::getStyle() const {
     213       57284 :         return _path ? _path->getStyle() : vg::DrawStyle::FillAndStroke;
     214             : }
     215             : 
     216       45396 : VectorPathRef & VectorPathRef::setTransform(const Mat4 &t) {
     217       45396 :         if (_path && _path->getTransform() == t) {
     218             :                 return *this;
     219             :         }
     220             : 
     221       44871 :         if (_copyOnWrite) {
     222          25 :                 copy();
     223             :         }
     224             : 
     225       44871 :         if (_path) {
     226       44871 :                 _path->setTransform(t);
     227       44871 :                 if (_image) { _image->setDirty(); }
     228             :         }
     229             :         return *this;
     230             : }
     231             : 
     232          25 : VectorPathRef & VectorPathRef::applyTransform(const Mat4 &t) {
     233          25 :         if (_copyOnWrite) {
     234          25 :                 copy();
     235             :         }
     236             : 
     237          25 :         if (_path) {
     238          25 :                 _path->applyTransform(t);
     239          25 :                 if (_image) { _image->setDirty(); }
     240             :         }
     241          25 :         return *this;
     242             : }
     243             : 
     244          25 : const Mat4 &VectorPathRef::getTransform() const {
     245          25 :         return _path ? _path->getTransform() : Mat4::IDENTITY;
     246             : }
     247             : 
     248      474143 : VectorPathRef & VectorPathRef::setAntialiased(bool value) {
     249      474143 :         if (_path && _path->isAntialiased() == value) {
     250             :                 return *this;
     251             :         }
     252             : 
     253      190643 :         if (_copyOnWrite) {
     254           0 :                 copy();
     255             :         }
     256             : 
     257      190643 :         if (_path) {
     258      190643 :                 _path->setAntialiased(value);
     259      190643 :                 if (_image) { _image->setDirty(); }
     260             :         }
     261             :         return *this;
     262             : }
     263             : 
     264       60015 : bool VectorPathRef::isAntialiased() const {
     265       60015 :         return _path ? _path->isAntialiased() : false;
     266             : }
     267             : 
     268          25 : VectorPathRef & VectorPathRef::clear() {
     269          25 :         if (_copyOnWrite) {
     270          25 :                 copy();
     271             :         }
     272             : 
     273          25 :         if (_path) {
     274          25 :                 _path->clear();
     275          25 :                 if (_image) { _image->setDirty(); }
     276             :         }
     277          25 :         return *this;
     278             : }
     279             : 
     280          25 : StringView VectorPathRef::getId() const {
     281          25 :         return _id;
     282             : }
     283             : 
     284          50 : bool VectorPathRef::empty() const {
     285          50 :         return _path ? _path->empty() : true;
     286             : }
     287             : 
     288          50 : bool VectorPathRef::valid() const {
     289          50 :         return _path && _image;
     290             : }
     291             : 
     292          25 : VectorPathRef::operator bool() const {
     293          25 :         return valid() && !empty();
     294             : }
     295             : 
     296          50 : void VectorPathRef::setPath(Rc<VectorPath> &&path) {
     297          50 :         _path = move(path);
     298          50 :         _copyOnWrite = false;
     299          50 : }
     300             : 
     301      611981 : VectorPath *VectorPathRef::getPath() const {
     302      611981 :         return _path;
     303             : }
     304             : 
     305      484243 : void VectorPathRef::markCopyOnWrite() {
     306      484243 :         _copyOnWrite = true;
     307      484243 : }
     308             : 
     309      546703 : void VectorPathRef::setImage(VectorImage *image) {
     310      546703 :         _image = image;
     311      546703 : }
     312             : 
     313         225 : void VectorPathRef::copy() {
     314         225 :         if (_copyOnWrite) {
     315         225 :                 if (_image) {
     316         225 :                         _path = _image->copyPath(_id);
     317             :                 }
     318         225 :                 _copyOnWrite = false;
     319             :         }
     320         225 : }
     321             : 
     322          75 : bool VectorImageData::init(VectorImage *image, Size2 size, Rect viewBox, Interface::VectorType<vg::PathXRef> &&order,
     323             :                 Interface::MapType<String, VectorPath> &&paths, uint16_t ids) {
     324          75 :         _imageSize = size;
     325          75 :         _image = image;
     326             : 
     327          75 :         if (!viewBox.equals(Rect::ZERO)) {
     328          50 :                 const float scaleX = _imageSize.width / viewBox.size.width;
     329          50 :                 const float scaleY = _imageSize.height / viewBox.size.height;
     330          50 :                 _viewBoxTransform = Mat4::IDENTITY;
     331          50 :                 _viewBoxTransform.scale(scaleX, scaleY, 1.0f);
     332          50 :                 _viewBoxTransform.translate(-viewBox.origin.x, -viewBox.origin.y, 0.0f);
     333          50 :                 _viewBox = Rect(viewBox.origin.x * scaleX, viewBox.origin.y * scaleY,
     334             :                                 viewBox.size.width * scaleX, viewBox.size.height * scaleY);
     335             :         } else {
     336          25 :                 _viewBox = Rect(0, 0, _imageSize.width, _imageSize.height);
     337             :         }
     338             : 
     339          75 :         _nextId = ids;
     340          75 :         _order = move(order);
     341             : 
     342         150 :         for (auto &it : paths) {
     343          75 :                 _paths.emplace(it.first, Rc<VectorPath>::alloc(move(it.second)));
     344             :         }
     345             : 
     346          75 :         return true;
     347             : }
     348             : 
     349      548431 : bool VectorImageData::init(VectorImage *image, Size2 size, Rect viewBox) {
     350      548431 :         _imageSize = size;
     351      548431 :         _image = image;
     352      548431 :         _viewBox = viewBox;
     353      548431 :         return true;
     354             : }
     355             : 
     356         250 : bool VectorImageData::init(VectorImageData &data) {
     357         250 :         _allowBatchDrawing = data._allowBatchDrawing;
     358         250 :         _imageSize = data._imageSize;
     359         250 :         _viewBox = data._viewBox;
     360         250 :         _viewBoxTransform = data._viewBoxTransform;
     361         250 :         _order = data._order;
     362         250 :         _paths = data._paths;
     363         250 :         _nextId = data._nextId;
     364         250 :         _image = data._image;
     365         250 :         return true;
     366             : }
     367             : 
     368          25 : void VectorImageData::setImageSize(const Size2 &size) {
     369          25 :         _imageSize = size;
     370          25 : }
     371             : 
     372          75 : const Interface::MapType<Interface::StringType, Rc<VectorPath>> &VectorImageData::getPaths() const {
     373          75 :         return _paths;
     374             : }
     375             : 
     376         225 : Rc<VectorPath> VectorImageData::copyPath(StringView str) {
     377         225 :         auto it = _paths.find(str);
     378         225 :         if (it != _paths.end()) {
     379         225 :                 it->second = Rc<VectorPath>::alloc(*it->second);
     380         225 :                 return it->second;
     381             :         }
     382           0 :         return nullptr;
     383             : }
     384             : 
     385      546553 : uint16_t VectorImageData::getNextId() {
     386      546553 :         auto ret = _nextId;
     387      546553 :         ++ _nextId;
     388      546553 :         return ret;
     389             : }
     390             : 
     391      546678 : Rc<VectorPath> VectorImageData::addPath(StringView id, StringView cache, VectorPath &&path, Mat4 mat) {
     392      546678 :         String idStr;
     393      546678 :         if (id.empty()) {
     394           0 :                 idStr = mem_std::toString("auto-", getNextId());
     395           0 :                 id = idStr;
     396             :         }
     397             : 
     398      546678 :         Rc<VectorPath> ret;
     399      546678 :         auto it = _paths.find(id);
     400      546678 :         if (it == _paths.end()) {
     401      546628 :                 ret = _paths.emplace(id.str<Interface>(), Rc<VectorPath>::alloc(move(path))).first->second;
     402      546628 :                 _order.emplace_back(vg::PathXRef{id.str<Interface>(), cache.str<Interface>(), mat});
     403             :         } else {
     404          50 :                 ret = it->second = Rc<VectorPath>::alloc(move(path));
     405             :                 bool found = false;
     406         175 :                 for (auto &iit : _order) {
     407         125 :                         if (iit.id == id) {
     408          50 :                                 iit.mat = mat;
     409             :                                 found = true;
     410             :                         }
     411             :                 }
     412          50 :                 if (!found) {
     413           0 :                         _order.emplace_back(vg::PathXRef{id.str<Interface>(), cache.str<Interface>(), mat});
     414             :                 }
     415             :         }
     416             : 
     417      546678 :         return ret;
     418      546678 : }
     419             : 
     420          50 : void VectorImageData::removePath(StringView id) {
     421          50 :         auto it = _paths.find(id);
     422          50 :         if (it != _paths.end()) {
     423          50 :                 _paths.erase(it);
     424             :         }
     425             : 
     426          50 :         auto iit = _order.begin();
     427         225 :         while (iit != _order.end()) {
     428         175 :                 if (iit->id == id) {
     429          50 :                         iit = _order.erase(iit);
     430             :                 } else {
     431         125 :                         ++ iit;
     432             :                 }
     433             :         }
     434          50 : }
     435             : 
     436         710 : void VectorImageData::clear() {
     437         710 :         _paths.clear();
     438         710 :         _order.clear();
     439         710 : }
     440             : 
     441          25 : void VectorImageData::resetDrawOrder() {
     442          25 :         _order.clear();
     443         100 :         for (auto &it : _paths) {
     444          75 :                 _order.emplace_back(vg::PathXRef{it.first});
     445             :         }
     446          25 : }
     447             : 
     448             : #if MODULE_STAPPLER_BITMAP
     449          25 : bool VectorImage::isSvg(StringView str) {
     450          25 :         return bitmap::check(bitmap::FileFormat::Svg, (const uint8_t *)str.data(), str.size());
     451             : }
     452             : 
     453          25 : bool VectorImage::isSvg(BytesView data) {
     454          25 :         return bitmap::check(bitmap::FileFormat::Svg, data.data(), data.size());
     455             : }
     456             : 
     457             : #if MODULE_STAPPLER_FILESYSTEM
     458          25 : bool VectorImage::isSvg(FilePath file) {
     459          25 :         auto d = filesystem::readIntoMemory<Interface>(file.get(), 0, 512);
     460          50 :         return bitmap::check(bitmap::FileFormat::Svg, d.data(), d.size());
     461          25 : }
     462             : #endif
     463             : #endif // MODULE_STAPPLER_BITMAP
     464             : 
     465      600887 : VectorImage::~VectorImage() {
     466     1095109 :         for (auto &it : _paths) {
     467      546603 :                 it.second->setImage(nullptr);
     468             :         }
     469      600887 : }
     470             : 
     471          25 : bool VectorImage::init(Size2 size, StringView data) {
     472          25 :         VectorPath path;
     473          25 :         if (!path.init(data)) {
     474             :                 return false;
     475             :         }
     476          25 :         return init(size, std::move(path));
     477          25 : }
     478             : 
     479          50 : bool VectorImage::init(Size2 size, VectorPath && path) {
     480          50 :         _data = Rc<VectorImageData>::create(this, size, Rect(0, 0, size.width, size.height));
     481          50 :         addPath(move(path));
     482          50 :         return true;
     483             : }
     484             : 
     485      548381 : bool VectorImage::init(Size2 size) {
     486      548381 :         _data = Rc<VectorImageData>::create(this, size, Rect(0, 0, size.width, size.height));
     487      548381 :         return true;
     488             : }
     489             : 
     490          50 : bool VectorImage::init(StringView data) {
     491          50 :         String tmp = data.str<Interface>();
     492          50 :         vg::SvgReader reader;
     493          50 :         html::parse<vg::SvgReader, StringView, vg::SvgTag>(reader, StringView(tmp));
     494             : 
     495          50 :         if (!reader._paths.empty()) {
     496         100 :                 _data = Rc<VectorImageData>::create(this, Size2(reader._width, reader._height), reader._viewBox,
     497         100 :                                 move(reader._drawOrder), move(reader._paths), reader._nextId);
     498         100 :                 for (auto &it : _data->getPaths()) {
     499          50 :                         _paths.emplace(it.first, Rc<VectorPathRef>::create(this, it.first, it.second));
     500             :                 }
     501             : 
     502          50 :                 auto t = Mat4::IDENTITY;
     503          50 :                 t.scale(1, -1, 1);
     504          50 :                 t.translate(0, -reader._height, 0);
     505             : 
     506          50 :                 _data->setViewBoxTransform(t);
     507             : 
     508             :                 return true;
     509             :         } else {
     510           0 :                 log::error("layout::Image", "No paths found in input string");
     511             :         }
     512             : 
     513           0 :         return false;
     514          50 : }
     515             : 
     516          25 : bool VectorImage::init(BytesView data) {
     517          25 :         vg::SvgReader reader;
     518          25 :         html::parse<vg::SvgReader, StringView, vg::SvgTag>(reader, StringView((const char *)data.data(), data.size()));
     519             : 
     520          25 :         if (!reader._paths.empty()) {
     521          50 :                 _data = Rc<VectorImageData>::create(this, Size2(reader._width, reader._height), reader._viewBox,
     522          50 :                                 move(reader._drawOrder), move(reader._paths), reader._nextId);
     523          50 :                 for (auto &it : _data->getPaths()) {
     524          25 :                         _paths.emplace(it.first, Rc<VectorPathRef>::create(this, it.first, it.second));
     525             :                 }
     526             : 
     527          25 :                 auto t = Mat4::IDENTITY;
     528          25 :                 t.scale(1, -1, 1);
     529          25 :                 t.translate(0, -reader._height, 0);
     530             : 
     531          25 :                 _data->setViewBoxTransform(t);
     532             : 
     533             :                 return true;
     534             :         } else {
     535           0 :                 log::error("layout::Image", "No paths found in input data");
     536             :         }
     537             : 
     538           0 :         return false;
     539          25 : }
     540             : 
     541             : #if MODULE_STAPPLER_FILESYSTEM
     542          25 : bool VectorImage::init(FilePath path) {
     543          25 :         return init(filesystem::readTextFile<Interface>(path.get()));
     544             : }
     545             : #endif
     546             : 
     547          25 : void VectorImage::setImageSize(const Size2 &size) {
     548          25 :         if (size == _data->getImageSize()) {
     549             :                 return;
     550             :         }
     551             : 
     552          25 :         if (_copyOnWrite) {
     553          25 :                 copy();
     554             :         }
     555             : 
     556          25 :         _data->setImageSize(size);
     557             : }
     558             : 
     559      128884 : Size2 VectorImage::getImageSize() const {
     560      128884 :         return _data->getImageSize();
     561             : }
     562             : 
     563          25 : Rect VectorImage::getViewBox() const {
     564          25 :         return _data->getViewBox();
     565             : }
     566             : 
     567          50 : Rc<VectorPathRef> VectorImage::addPath(const VectorPath &path, StringView tag, StringView cache, Mat4 vec) {
     568          50 :         return addPath(VectorPath(path), tag, cache, vec);
     569             : }
     570             : 
     571      546678 : Rc<VectorPathRef> VectorImage::addPath(VectorPath &&path, StringView tag, StringView cache, Mat4 vec) {
     572      546678 :         if (_copyOnWrite) {
     573          25 :                 copy();
     574             :         }
     575             : 
     576      546678 :         String idStr;
     577      546678 :         if (tag.empty()) {
     578      546553 :                 idStr = mem_std::toString("auto-", _data->getNextId());
     579      546553 :                 tag = idStr;
     580             :         }
     581             : 
     582      546678 :         auto pathObj = _data->addPath(tag, cache, move(path), vec);
     583             : 
     584      546678 :         setDirty();
     585             : 
     586      546678 :         auto it = _paths.find(tag);
     587      546678 :         if (it == _paths.end()) {
     588      546628 :                 auto obj = Rc<VectorPathRef>::create(this, tag.str<Interface>(), move(pathObj));
     589      546628 :                 return _paths.emplace(idStr.empty() ? tag.str<Interface>() : move(idStr), move(obj)).first->second;
     590      546628 :         } else {
     591          50 :                 it->second->setPath(move(pathObj));
     592          50 :                 return it->second;
     593             :         }
     594      546678 : }
     595             : 
     596      546578 : Rc<VectorPathRef> VectorImage::addPath(StringView tag, StringView cache, Mat4 vec) {
     597      546578 :         return addPath(VectorPath(), tag, cache, vec);
     598             : }
     599             : 
     600          50 : Rc<VectorPathRef> VectorImage::getPath(StringView tag) const {
     601          50 :         auto it = _paths.find(tag);
     602          50 :         if (it != _paths.end()) {
     603          50 :                 return it->second;
     604             :         }
     605           0 :         return nullptr;
     606             : }
     607             : 
     608          25 : void VectorImage::removePath(const Rc<VectorPathRef> &path) {
     609          25 :         removePath(path->getId());
     610          25 : }
     611             : 
     612          50 : void VectorImage::removePath(StringView tag) {
     613          50 :         if (_copyOnWrite) {
     614          50 :                 copy();
     615             :         }
     616             : 
     617          50 :         _data->removePath(tag);
     618          50 :         auto it = _paths.find(tag);
     619          50 :         if (it != _paths.end()) {
     620          50 :                 it->second->setImage(nullptr);
     621          50 :                 _paths.erase(it);
     622             :         }
     623          50 :         setDirty();
     624          50 : }
     625             : 
     626         710 : void VectorImage::clear() {
     627         710 :         if (_copyOnWrite) {
     628          25 :                 copy();
     629             :         }
     630             : 
     631         710 :         _data->clear();
     632             : 
     633         760 :         for (auto &it : _paths) {
     634          50 :                 it.second->setImage(nullptr);
     635             :         }
     636         710 :         _paths.clear();
     637         710 :         setDirty();
     638         710 : }
     639             : 
     640          25 : const Interface::VectorType<PathXRef> &VectorImage::getDrawOrder() const {
     641          25 :         return _data->getDrawOrder();
     642             : }
     643             : 
     644          25 : void VectorImage::setDrawOrder(const Interface::VectorType<PathXRef> &vec) {
     645          25 :         if (_copyOnWrite) {
     646          25 :                 copy();
     647             :         }
     648             : 
     649          25 :         _data->setDrawOrder(Interface::VectorType<PathXRef>(vec));
     650          25 :         setDirty();
     651          25 : }
     652             : 
     653          25 : void VectorImage::setDrawOrder(Interface::VectorType<PathXRef> &&vec) {
     654          25 :         if (_copyOnWrite) {
     655          25 :                 copy();
     656             :         }
     657             : 
     658          25 :         _data->setDrawOrder(move(vec));
     659          25 :         setDirty();
     660          25 : }
     661             : 
     662          25 : void VectorImage::resetDrawOrder() {
     663          25 :         if (_copyOnWrite) {
     664          25 :                 copy();
     665             :         }
     666             : 
     667          25 :         _data->resetDrawOrder();
     668          25 :         setDirty();
     669          25 : }
     670             : 
     671          25 : void VectorImage::setViewBoxTransform(const Mat4 &m) {
     672          25 :         if (_data->getViewBoxTransform() == m) {
     673             :                 return;
     674             :         }
     675             : 
     676          25 :         if (_copyOnWrite) {
     677          25 :                 copy();
     678             :         }
     679             : 
     680          25 :         _data->setViewBoxTransform(m);
     681          25 :         setDirty();
     682             : }
     683             : 
     684          25 : const Mat4 &VectorImage::getViewBoxTransform() const {
     685          25 :         return _data->getViewBoxTransform();
     686             : }
     687             : 
     688          50 : void VectorImage::setBatchDrawing(bool value) {
     689          50 :         if (_data->isBatchDrawing() == value) {
     690             :                 return;
     691             :         }
     692             : 
     693          25 :         if (_copyOnWrite) {
     694          25 :                 copy();
     695             :         }
     696             : 
     697          25 :         _data->setBatchDrawing(value);
     698             : }
     699             : 
     700          25 : bool VectorImage::isBatchDrawing() const {
     701          25 :         return _data->isBatchDrawing();
     702             : }
     703             : 
     704      483351 : Rc<VectorImageData> VectorImage::popData() {
     705      483351 :         markCopyOnWrite();
     706      483351 :         return _data;
     707             : }
     708             : 
     709      153940 : bool VectorImage::isDirty() const {
     710      153940 :         return _dirty;
     711             : }
     712             : 
     713     1342083 : void VectorImage::setDirty() {
     714     1342083 :         _dirty = true;
     715     1342083 : }
     716             : 
     717       57851 : void VectorImage::clearDirty() {
     718       57851 :         _dirty = false;
     719       57851 : }
     720             : 
     721         475 : void VectorImage::copy() {
     722         475 :         if (_copyOnWrite) {
     723         250 :                 _data = Rc<VectorImageData>::create(*_data.get());
     724         250 :                 _copyOnWrite = false;
     725             :         }
     726         475 : }
     727             : 
     728      483351 : void VectorImage::markCopyOnWrite() {
     729      483351 :         _copyOnWrite = true;
     730      967369 :         for (auto &it : _paths) {
     731      484018 :                 it.second->markCopyOnWrite();
     732             :         }
     733      483351 : }
     734             : 
     735         225 : Rc<VectorPath> VectorImage::copyPath(StringView str) {
     736         225 :         copy();
     737         225 :         return _data->copyPath(str);
     738             : }
     739             : 
     740             : }

Generated by: LCOV version 1.14