LCOV - code coverage report
Current view: top level - muse/framework/draw/utils - drawdatajson.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 60.7 % 392 238
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "drawdatajson.h"
      23              : 
      24              : #include "global/serialization/json.h"
      25              : 
      26              : #include "log.h"
      27              : 
      28              : using namespace muse;
      29              : using namespace muse::draw;
      30              : 
      31         5071 : static int rtoi(double v)
      32              : {
      33         5071 :     return static_cast<int>(v * 1000.0);
      34              : }
      35              : 
      36           26 : static double itor(int v)
      37              : {
      38           26 :     return static_cast<double>(v) / 1000.0;
      39              : }
      40              : 
      41          409 : static JsonArray toArr(const std::vector<double>& vv)
      42              : {
      43          409 :     JsonArray a;
      44          409 :     for (double v : vv) {
      45            0 :         a.append(rtoi(v));
      46              :     }
      47          409 :     return a;
      48            0 : }
      49              : 
      50            4 : static void fromArr(const JsonArray& arr, std::vector<double>& vv)
      51              : {
      52            4 :     for (size_t i = 0; i < arr.size(); ++i) {
      53            0 :         vv.push_back(itor(arr.at(i).toDouble()));
      54              :     }
      55            4 : }
      56              : 
      57          409 : static JsonObject toObj(const Pen& pen)
      58              : {
      59          409 :     JsonObject obj;
      60          818 :     obj["style"] = static_cast<int>(pen.style());
      61          818 :     obj["capStyle"] = static_cast<int>(pen.capStyle());
      62          818 :     obj["joinStyle"] = static_cast<int>(pen.joinStyle());
      63          818 :     obj["miterLimit"] = pen.miterLimit();
      64         1227 :     obj["color"] = pen.color().toString();
      65          818 :     obj["width"] = pen.widthF();
      66         1227 :     obj["dashPattern"] = toArr(pen.dashPattern());
      67          409 :     return obj;
      68            0 : }
      69              : 
      70            4 : static void fromObj(const JsonObject& obj, Pen& pen)
      71              : {
      72           12 :     pen.setStyle(static_cast<PenStyle>(obj.value("style").toInt()));
      73           12 :     pen.setCapStyle(static_cast<PenCapStyle>(obj.value("capStyle").toInt()));
      74           12 :     pen.setJoinStyle(static_cast<PenJoinStyle>(obj.value("joinStyle").toInt()));
      75            8 :     if (obj.contains("miterLimit")) {
      76            6 :         pen.setMiterLimit(obj.value("miterLimit").toDouble());
      77              :     }
      78           12 :     pen.setColor(Color(obj.value("color").toStdString().c_str()));
      79           12 :     pen.setWidthF(obj.value("width").toDouble());
      80              : 
      81            4 :     std::vector<double> dp;
      82           12 :     fromArr(obj.value("dashPattern").toArray(), dp);
      83            4 :     pen.setDashPattern(dp);
      84            4 : }
      85              : 
      86          409 : static JsonObject toObj(const Brush& brush)
      87              : {
      88          409 :     JsonObject obj;
      89          818 :     obj["style"] = static_cast<int>(brush.style());
      90         1227 :     obj["color"] = brush.color().toString();
      91          409 :     return obj;
      92            0 : }
      93              : 
      94            4 : static void fromObj(const JsonObject& obj, Brush& brush)
      95              : {
      96            8 :     brush.setStyle(static_cast<BrushStyle>(obj["style"].toInt()));
      97            4 :     brush.setColor(Color(obj["color"].toStdString().c_str()));
      98            4 : }
      99              : 
     100          401 : static JsonObject toObj(const Font& font)
     101              : {
     102          401 :     JsonObject obj;
     103         1203 :     obj["family"] = font.family().id();
     104          802 :     obj["type"] = static_cast<int>(font.type());
     105          802 :     obj["pointSize"] = font.pointSizeF();
     106          802 :     obj["weight"] = font.weight();
     107          802 :     obj["bold"] = font.bold();
     108          802 :     obj["italic"] = font.italic();
     109          802 :     obj["underline"] = font.underline();
     110          802 :     obj["strike"] = font.strike();
     111          802 :     obj["hinting"] = static_cast<int>(font.hinting());
     112          802 :     obj["no_merging"] = font.noFontMerging();
     113          401 :     return obj;
     114            0 : }
     115              : 
     116            2 : static void fromObj(const JsonObject& obj, Font& font)
     117              : {
     118           10 :     font.setFamily(obj.value("family").toString(), static_cast<Font::Type>(obj.value("type").toInt()));
     119            6 :     font.setPointSizeF(obj.value("pointSize").toDouble());
     120            6 :     font.setWeight(static_cast<Font::Weight>(obj.value("weight").toInt()));
     121            6 :     font.setBold(obj.value("bold").toBool());
     122            6 :     font.setItalic(obj.value("italic").toBool());
     123            6 :     font.setUnderline(obj.value("underline").toBool());
     124            6 :     font.setStrike(obj.value("strike").toBool());
     125            6 :     font.setHinting(static_cast<Font::Hinting>(obj.value("hinting").toInt()));
     126            6 :     font.setNoFontMerging(obj.value("no_merging").toBool());
     127            2 : }
     128              : 
     129          401 : static JsonArray toArr(const Transform& t)
     130              : {
     131              :     return JsonArray({ rtoi(t.m11()), rtoi(t.m12()), rtoi(t.m13()),
     132              :                        rtoi(t.m21()), rtoi(t.m22()), rtoi(t.m23()),
     133         4010 :                        rtoi(t.m31()), rtoi(t.m32()), rtoi(t.m33()) });
     134          401 : }
     135              : 
     136            2 : static void fromArr(const JsonArray& arr, Transform& t)
     137              : {
     138            2 :     IF_ASSERT_FAILED(arr.size() == 9) {
     139            0 :         return;
     140              :     }
     141              : 
     142           12 :     t.setMatrix(itor(arr.at(0).toInt()), itor(arr.at(1).toInt()), itor(arr.at(2).toInt()),
     143            8 :                 itor(arr.at(3).toInt()), itor(arr.at(4).toInt()), itor(arr.at(5).toInt()),
     144            8 :                 itor(arr.at(6).toInt()), itor(arr.at(7).toInt()), itor(arr.at(8).toInt()));
     145              : }
     146              : 
     147          677 : static JsonArray toArr(const PointF& p)
     148              : {
     149         2031 :     return JsonArray({ rtoi(p.x()), rtoi(p.y()) });
     150          677 : }
     151              : 
     152            0 : static void fromArr(const JsonArray& arr, PointF& p)
     153              : {
     154            0 :     IF_ASSERT_FAILED(arr.size() == 2) {
     155            0 :         return;
     156              :     }
     157            0 :     p.setX(itor(arr.at(0).toInt()));
     158            0 :     p.setY(itor(arr.at(1).toInt()));
     159              : }
     160              : 
     161           12 : static JsonArray toArr(const RectF& r)
     162              : {
     163           60 :     return JsonArray({ rtoi(r.x()), rtoi(r.y()), rtoi(r.width()), rtoi(r.height()) });
     164           12 : }
     165              : 
     166            2 : static void fromArr(const JsonArray& arr, RectF& r)
     167              : {
     168            2 :     IF_ASSERT_FAILED(arr.size() == 4) {
     169            0 :         return;
     170              :     }
     171            2 :     r = RectF(itor(arr.at(0).toInt()), itor(arr.at(1).toInt()), itor(arr.at(2).toInt()), itor(arr.at(3).toInt()));
     172              : }
     173              : 
     174            0 : static JsonArray toArr(const Size& sz)
     175              : {
     176            0 :     return JsonArray({ sz.width(), sz.height() });
     177            0 : }
     178              : 
     179            0 : static void fromArr(const JsonArray& arr, Size& sz)
     180              : {
     181            0 :     IF_ASSERT_FAILED(arr.size() == 2) {
     182            0 :         return;
     183              :     }
     184            0 :     sz = Size(arr.at(0).toInt(), arr.at(1).toInt());
     185              : }
     186              : 
     187          401 : static JsonObject toObj(const DrawData::State& st)
     188              : {
     189          401 :     JsonObject obj;
     190         1203 :     obj["pen"] = toObj(st.pen);
     191         1203 :     obj["brush"] = toObj(st.brush);
     192         1203 :     obj["font"] = toObj(st.font);
     193          802 :     obj["isAntialiasing"] = st.isAntialiasing;
     194         1203 :     obj["transform"] = toArr(st.transform);
     195          802 :     obj["compositionMode"] = static_cast<int>(st.compositionMode);
     196          401 :     return obj;
     197            0 : }
     198              : 
     199            2 : static void fromObj(const JsonObject& obj, DrawData::State& st)
     200              : {
     201            4 :     fromObj(obj["pen"].toObject(), st.pen);
     202            4 :     fromObj(obj["brush"].toObject(), st.brush);
     203            6 :     fromObj(obj["font"].toObject(), st.font);
     204            2 :     st.isAntialiasing = obj["isAntialiasing"].toBool();
     205            6 :     fromArr(obj["transform"].toArray(), st.transform);
     206            2 :     st.compositionMode = static_cast<CompositionMode>(obj["compositionMode"].toInt());
     207            2 : }
     208              : 
     209            8 : static JsonObject toObj(const PainterPath& path)
     210              : {
     211            8 :     JsonObject obj;
     212           16 :     obj["fillRule"] = static_cast<int>(path.fillRule());
     213              : 
     214            8 :     JsonArray elsArr;
     215           38 :     for (size_t i = 0; i < path.elementCount(); ++i) {
     216           30 :         PainterPath::Element e = path.elementAt(i);
     217          120 :         elsArr.append(JsonArray({ static_cast<int>(e.type), rtoi(e.x), rtoi(e.y) }));
     218              :     }
     219            8 :     obj["elements"] = elsArr;
     220            8 :     return obj;
     221           38 : }
     222              : 
     223            8 : static JsonObject toObj(const DrawPath& path)
     224              : {
     225            8 :     JsonObject obj;
     226           24 :     obj["path"] = toObj(path.path);
     227           24 :     obj["pen"] = toObj(path.pen);
     228           24 :     obj["brush"] = toObj(path.brush);
     229           16 :     obj["mode"] = static_cast<int>(path.mode);
     230            8 :     return obj;
     231            0 : }
     232              : 
     233            2 : static void fromObj(const JsonObject& obj, PainterPath& path)
     234              : {
     235            4 :     path.setFillRule(static_cast<PainterPath::FillRule>(obj["fillRule"].toInt()));
     236              : 
     237            2 :     JsonArray elsArr = obj["elements"].toArray();
     238            2 :     std::vector<PainterPath::Element> curveEls;
     239            2 :     for (size_t i = 0; i < elsArr.size(); ++i) {
     240            0 :         JsonArray elArr = elsArr.at(i).toArray();
     241            0 :         IF_ASSERT_FAILED(elArr.size() == 3) {
     242            0 :             continue;
     243              :         }
     244              : 
     245            0 :         PainterPath::ElementType type = static_cast<PainterPath::ElementType>(elArr.at(0).toInt());
     246            0 :         double x = itor(elArr.at(1).toInt());
     247            0 :         double y = itor(elArr.at(2).toInt());
     248              : 
     249            0 :         switch (type) {
     250            0 :         case PainterPath::ElementType::MoveToElement: {
     251            0 :             path.moveTo(x, y);
     252            0 :         } break;
     253            0 :         case PainterPath::ElementType::LineToElement: {
     254            0 :             path.lineTo(x, y);
     255            0 :         } break;
     256            0 :         case PainterPath::ElementType::CurveToElement: {
     257            0 :             IF_ASSERT_FAILED(curveEls.empty()) {
     258            0 :                 continue;
     259              :             }
     260            0 :             PainterPath::Element e(x, y, type);
     261            0 :             curveEls.push_back(std::move(e));
     262            0 :         } break;
     263            0 :         case PainterPath::ElementType::CurveToDataElement: {
     264            0 :             if (curveEls.size() == 1) { // only CurveToElement
     265            0 :                 PainterPath::Element e(x, y, type);
     266            0 :                 curveEls.push_back(std::move(e));
     267            0 :                 continue;
     268            0 :             }
     269              : 
     270            0 :             IF_ASSERT_FAILED(curveEls.size() == 2) { // must be CurveToElement and one CurveToDataElement
     271            0 :                 curveEls.clear();
     272            0 :                 continue;
     273              :             }
     274              : 
     275            0 :             path.cubicTo(curveEls.at(0).x, curveEls.at(0).y, curveEls.at(1).x, curveEls.at(1).y, x, y);
     276            0 :             curveEls.clear();
     277            0 :         } break;
     278              :         }
     279            0 :     }
     280            2 : }
     281              : 
     282            2 : static void fromObj(const JsonObject& obj, DrawPath& path)
     283              : {
     284            4 :     fromObj(obj["path"].toObject(), path.path);
     285            4 :     fromObj(obj["pen"].toObject(), path.pen);
     286            6 :     fromObj(obj["brush"].toObject(), path.brush);
     287            2 :     path.mode = static_cast<DrawMode>(obj["mode"].toInt());
     288            2 : }
     289              : 
     290          223 : static JsonArray toArr(const PolygonF& pol)
     291              : {
     292          223 :     JsonArray a;
     293          669 :     for (const PointF& p : pol) {
     294          446 :         a.append(toArr(p));
     295              :     }
     296          223 :     return a;
     297            0 : }
     298              : 
     299            0 : static void fromArr(const JsonArray& arr, PolygonF& pol)
     300              : {
     301            0 :     pol.reserve(arr.size());
     302            0 :     for (size_t i = 0; i < arr.size(); ++i) {
     303            0 :         PointF p;
     304            0 :         fromArr(arr.at(i).toArray(), p);
     305            0 :         pol.push_back(std::move(p));
     306              :     }
     307            0 : }
     308              : 
     309          223 : static JsonObject toObj(const DrawPolygon& pol)
     310              : {
     311          223 :     JsonObject obj;
     312          669 :     obj["polygon"] = toArr(pol.polygon);
     313          446 :     obj["mode"] = static_cast<int>(pol.mode);
     314          223 :     return obj;
     315            0 : }
     316              : 
     317            0 : static void fromObj(const JsonObject& obj, DrawPolygon& pol)
     318              : {
     319            0 :     fromArr(obj["polygon"].toArray(), pol.polygon);
     320            0 :     pol.mode = static_cast<PolygonMode>(obj["mode"].toInt());
     321            0 : }
     322              : 
     323          231 : static JsonObject toObj(const DrawText& text)
     324              : {
     325          231 :     JsonObject o;
     326          231 :     if (text.mode == DrawText::Point) {
     327          693 :         o["point"] = toArr(text.rect.topLeft());
     328              :     } else {
     329            0 :         o["rect"] = toArr(text.rect);
     330              :     }
     331          462 :     o["alignment"] = static_cast<int>(text.alignment);
     332          462 :     o["textFlags"] = static_cast<int>(text.textFlags);
     333          462 :     o["text"] = text.text;
     334          231 :     return o;
     335            0 : }
     336              : 
     337            0 : static void fromObj(const JsonObject& obj, DrawText& text)
     338              : {
     339            0 :     if (obj.contains("point")) {
     340            0 :         PointF point;
     341            0 :         fromArr(obj["point"].toArray(), point);
     342            0 :         text.mode = DrawText::Point;
     343            0 :         text.rect = RectF(point, SizeF());
     344              :     } else {
     345            0 :         fromArr(obj["rect"].toArray(), text.rect);
     346            0 :         text.mode = DrawText::Rect;
     347              :     }
     348            0 :     text.alignment = static_cast<Alignment>(obj["alignment"].toInt());
     349            0 :     text.textFlags = static_cast<TextFlags>(obj["textFlags"].toInt());
     350            0 :     text.text = obj["text"].toString();
     351            0 : }
     352              : 
     353            0 : static JsonObject toObj(const DrawPixmap& pm)
     354              : {
     355            0 :     JsonObject o;
     356            0 :     if (pm.mode == DrawPixmap::Single) {
     357            0 :         o["point"] = toArr(pm.rect.topLeft());
     358              :     } else {
     359            0 :         o["rect"] = toArr(pm.rect);
     360            0 :         o["offset"] = toArr(pm.offset);
     361              :     }
     362            0 :     o["pmSize"] = toArr(pm.pm.size());
     363            0 :     return o;
     364            0 : }
     365              : 
     366            0 : static void fromObj(const JsonObject& obj, DrawPixmap& pm)
     367              : {
     368            0 :     if (obj.contains("point")) {
     369            0 :         pm.mode = DrawPixmap::Single;
     370            0 :         PointF point;
     371            0 :         fromArr(obj["point"].toArray(), point);
     372            0 :         pm.rect = RectF(point, SizeF());
     373              :     } else {
     374            0 :         pm.mode = DrawPixmap::Tiled;
     375            0 :         fromArr(obj["rect"].toArray(), pm.rect);
     376            0 :         fromArr(obj["offset"].toArray(), pm.offset);
     377              :     }
     378              : 
     379            0 :     Size size;
     380            0 :     fromArr(obj["pmSize"].toArray(), size);
     381            0 :     pm.pm = Pixmap(size);
     382            0 : }
     383              : 
     384              : template<class T>
     385          380 : static JsonArray toArr(const std::vector<T>& vals)
     386              : {
     387          380 :     JsonArray arr;
     388          842 :     for (size_t i = 0; i < vals.size(); ++i) {
     389          462 :         arr << toObj(vals.at(i));
     390              :     }
     391          380 :     return arr;
     392            0 : }
     393              : 
     394              : template<class T>
     395            2 : static void fromArr(const JsonArray& arr, std::vector<T>& vals)
     396              : {
     397            2 :     vals.reserve(arr.size());
     398            4 :     for (size_t i = 0; i < arr.size(); ++i) {
     399            2 :         T val;
     400            2 :         fromObj(arr.at(i).toObject(), val);
     401            2 :         vals.push_back(std::move(val));
     402              :     }
     403            2 : }
     404              : 
     405           23 : static JsonObject toObj(const DrawData::Item& obj)
     406              : {
     407              :     //! NOTE 'a' added to the beginning of some field names for convenient sorting
     408              : 
     409           23 :     JsonObject objObj;
     410           46 :     objObj["a_name"] = obj.name;
     411              : 
     412           23 :     JsonArray childrenArr;
     413           34 :     for (const DrawData::Item& ch : obj.chilren) {
     414           11 :         childrenArr.append(toObj(ch));
     415              :     }
     416           23 :     objObj["children"] = childrenArr;
     417              : 
     418           23 :     JsonArray datasArr;
     419          403 :     for (const DrawData::Data& data : obj.datas) {
     420          380 :         if (data.empty()) {
     421            0 :             continue;
     422              :         }
     423              : 
     424          380 :         JsonObject dataObj;
     425          760 :         dataObj["state"] = data.state;
     426          380 :         if (!data.paths.empty()) {
     427           24 :             dataObj["paths"] = toArr(data.paths);
     428              :         }
     429          380 :         if (!data.polygons.empty()) {
     430          423 :             dataObj["polygons"] = toArr(data.polygons);
     431              :         }
     432          380 :         if (!data.texts.empty()) {
     433          693 :             dataObj["texts"] = toArr(data.texts);
     434              :         }
     435          380 :         if (!data.pixmaps.empty()) {
     436            0 :             dataObj["pixmaps"] = toArr(data.pixmaps);
     437              :         }
     438              : 
     439          380 :         datasArr.append(dataObj);
     440          380 :     }
     441           23 :     objObj["datas"] = datasArr;
     442              : 
     443           23 :     return objObj;
     444           23 : }
     445              : 
     446            2 : static void fromObj(const JsonObject& objObj, DrawData::Item& obj)
     447              : {
     448            6 :     obj.name = objObj.value("a_name").toString().toStdString();
     449            2 :     JsonArray childrenArr = objObj["children"].toArray();
     450            2 :     for (size_t j = 0; j < childrenArr.size(); ++j) {
     451            0 :         DrawData::Item& ch = obj.chilren.emplace_back();
     452            0 :         const JsonObject childObj = childrenArr.at(j).toObject();
     453            0 :         fromObj(childObj, ch);
     454            0 :     }
     455              : 
     456            2 :     JsonArray datasArr = objObj["datas"].toArray();
     457            4 :     for (size_t j = 0; j < datasArr.size(); ++j) {
     458            2 :         const JsonObject dataObj = datasArr.at(j).toObject();
     459            2 :         DrawData::Data data;
     460            4 :         data.state = dataObj["state"].toInt();
     461            4 :         if (dataObj.contains("paths")) {
     462            6 :             fromArr(dataObj.value("paths").toArray(), data.paths);
     463              :         }
     464            4 :         if (dataObj.contains("polygons")) {
     465            0 :             fromArr(dataObj.value("polygons").toArray(), data.polygons);
     466              :         }
     467            4 :         if (dataObj.contains("texts")) {
     468            0 :             fromArr(dataObj.value("texts").toArray(), data.texts);
     469              :         }
     470            4 :         if (dataObj.contains("pixmaps")) {
     471            0 :             fromArr(dataObj.value("pixmaps").toArray(), data.pixmaps);
     472              :         }
     473              : 
     474            2 :         obj.datas.push_back(std::move(data));
     475            2 :     }
     476            2 : }
     477              : 
     478           12 : void DrawDataJson::toJson(JsonObject& root, const DrawDataPtr& dd)
     479              : {
     480              :     //! NOTE 'a' added to the beginning of some field names for convenient sorting
     481              : 
     482           24 :     root["a_name"] = dd->name;
     483           36 :     root["a_viewport"] = toArr(dd->viewport);
     484              : 
     485              :     // item
     486           36 :     root["item"] = toObj(dd->item);
     487              : 
     488              :     // states
     489           12 :     JsonObject stateObj;
     490          413 :     for (auto it = dd->states.cbegin(); it != dd->states.cend(); ++it) {
     491          401 :         stateObj[std::to_string(it->first)] = toObj(it->second);
     492              :     }
     493           12 :     root["states"] = stateObj;
     494           12 : }
     495              : 
     496            2 : void DrawDataJson::fromJson(const JsonObject& root, DrawDataPtr& dd)
     497              : {
     498              :     // read states
     499              :     {
     500            6 :         const JsonObject obj = root.value("states").toObject();
     501            2 :         std::vector<std::string> keys = obj.keys();
     502            4 :         for (const std::string& k : keys) {
     503            2 :             DrawData::State state;
     504            2 :             fromObj(obj.value(k).toObject(), state);
     505            2 :             dd->states[std::stoi(k)] = state;
     506            2 :         }
     507            2 :     }
     508              : 
     509            6 :     dd->name = root.value("a_name").toStdString();
     510            6 :     fromArr(root.value("a_viewport").toArray(), dd->viewport);
     511              : 
     512            6 :     JsonObject itemObj = root.value("item").toObject();
     513            2 :     fromObj(itemObj, dd->item);
     514            2 : }
     515              : 
     516           12 : ByteArray DrawDataJson::toJson(const DrawDataPtr& data, bool prettify)
     517              : {
     518           12 :     IF_ASSERT_FAILED(data) {
     519            0 :         return ByteArray();
     520              :     }
     521              : 
     522           12 :     JsonObject root;
     523           12 :     toJson(root, data);
     524           12 :     return JsonDocument(root).toJson(prettify ? JsonDocument::Format::Indented : JsonDocument::Format::Compact);
     525           12 : }
     526              : 
     527            2 : RetVal<DrawDataPtr> DrawDataJson::fromJson(const ByteArray& json)
     528              : {
     529            2 :     std::string err;
     530            2 :     JsonDocument doc = JsonDocument::fromJson(json, &err);
     531            2 :     if (!err.empty()) {
     532            0 :         RetVal<DrawDataPtr> rv;
     533            0 :         rv.ret = make_ret(Ret::Code::UnknownError, err);
     534            0 :         return rv;
     535            0 :     }
     536              : 
     537            2 :     const JsonObject root = doc.rootObject();
     538            2 :     DrawDataPtr dd = std::make_shared<DrawData>();
     539            2 :     fromJson(root, dd);
     540            2 :     return RetVal<DrawDataPtr>::make_ok(dd);
     541            2 : }
     542              : 
     543            0 : ByteArray DrawDataJson::diffToJson(const Diff& diff)
     544              : {
     545            0 :     IF_ASSERT_FAILED(diff.dataAdded && diff.dataRemoved) {
     546            0 :         return ByteArray();
     547              :     }
     548              : 
     549            0 :     JsonObject added;
     550            0 :     toJson(added, diff.dataAdded);
     551              : 
     552            0 :     JsonObject removed;
     553            0 :     toJson(removed, diff.dataRemoved);
     554              : 
     555            0 :     JsonObject root;
     556            0 :     root["type"] = "diff";
     557            0 :     root["added"] = added;
     558            0 :     root["removed"] = removed;
     559            0 :     return JsonDocument(root).toJson(JsonDocument::Format::Indented);
     560            0 : }
     561              : 
     562            0 : RetVal<Diff> DrawDataJson::diffFromJson(const ByteArray& json)
     563              : {
     564            0 :     std::string err;
     565            0 :     JsonDocument doc = JsonDocument::fromJson(json, &err);
     566            0 :     if (!err.empty()) {
     567            0 :         RetVal<Diff> rv;
     568            0 :         rv.ret = make_ret(Ret::Code::UnknownError, err);
     569            0 :         return rv;
     570            0 :     }
     571              : 
     572            0 :     const JsonObject root = doc.rootObject();
     573            0 :     IF_ASSERT_FAILED(root.value("type").toStdString() == "diff") {
     574            0 :         RetVal<Diff> rv;
     575            0 :         rv.ret = make_ret(Ret::Code::UnknownError, err);
     576            0 :         return rv;
     577            0 :     }
     578              : 
     579            0 :     Diff diff;
     580            0 :     diff.dataAdded = std::make_shared<DrawData>();
     581            0 :     diff.dataRemoved = std::make_shared<DrawData>();
     582              : 
     583            0 :     JsonObject added = root.value("added").toObject();
     584            0 :     fromJson(added, diff.dataAdded);
     585              : 
     586            0 :     JsonObject removed = root.value("removed").toObject();
     587            0 :     fromJson(removed, diff.dataRemoved);
     588              : 
     589            0 :     return RetVal<Diff>::make_ok(diff);
     590            0 : }
        

Generated by: LCOV version 2.0-1